summaryrefslogtreecommitdiffstats
path: root/contrib/ofed/management
diff options
context:
space:
mode:
authorjeff <jeff@FreeBSD.org>2011-03-21 09:58:24 +0000
committerjeff <jeff@FreeBSD.org>2011-03-21 09:58:24 +0000
commit5115240a6cdc054f7eea804355742f97c74578d8 (patch)
tree3051c12f4ce44a65c025b72ec5821b35b2ec46be /contrib/ofed/management
parent2d7d8c05e7404fbebf1f0fe24c13bc5bb58d2338 (diff)
downloadFreeBSD-src-5115240a6cdc054f7eea804355742f97c74578d8.zip
FreeBSD-src-5115240a6cdc054f7eea804355742f97c74578d8.tar.gz
- Merge in OFED 1.5.3 from projects/ofed/head
Diffstat (limited to 'contrib/ofed/management')
-rw-r--r--contrib/ofed/management/AUTHORS3
-rw-r--r--contrib/ofed/management/COPYING384
-rw-r--r--contrib/ofed/management/ChangeLog0
-rw-r--r--contrib/ofed/management/INSTALL0
-rw-r--r--contrib/ofed/management/Makefile21
-rw-r--r--contrib/ofed/management/NEWS0
-rw-r--r--contrib/ofed/management/README132
-rw-r--r--contrib/ofed/management/doc/diagtools-proposal.txt169
-rw-r--r--contrib/ofed/management/doc/diagtools.txt565
-rw-r--r--contrib/ofed/management/doc/ibtracer.txt106
-rw-r--r--contrib/ofed/management/doc/libibmad.txt687
-rw-r--r--contrib/ofed/management/doc/libibumad.txt392
-rwxr-xr-xcontrib/ofed/management/gen_chlog.sh74
-rwxr-xr-xcontrib/ofed/management/gen_ver.sh38
-rw-r--r--contrib/ofed/management/infiniband-diags/COPYING384
-rw-r--r--contrib/ofed/management/infiniband-diags/ChangeLog470
-rw-r--r--contrib/ofed/management/infiniband-diags/Makefile.am125
-rw-r--r--contrib/ofed/management/infiniband-diags/README564
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/autogen.sh11
-rw-r--r--contrib/ofed/management/infiniband-diags/configure.in170
-rw-r--r--contrib/ofed/management/infiniband-diags/include/grouping.h113
-rw-r--r--contrib/ofed/management/infiniband-diags/include/ibdiag_common.h62
-rw-r--r--contrib/ofed/management/infiniband-diags/include/ibdiag_version.h39
-rw-r--r--contrib/ofed/management/infiniband-diags/include/ibdiag_version.h.in39
-rw-r--r--contrib/ofed/management/infiniband-diags/include/ibnetdiscover.h107
-rw-r--r--contrib/ofed/management/infiniband-diags/infiniband-diags.spec.in194
-rw-r--r--contrib/ofed/management/infiniband-diags/man/check_lft_balance.842
-rw-r--r--contrib/ofed/management/infiniband-diags/man/dump_lfts.850
-rw-r--r--contrib/ofed/management/infiniband-diags/man/dump_mfts.845
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibaddr.8109
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibcheckerrors.841
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibcheckerrs.859
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibchecknet.836
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibchecknode.843
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibcheckport.843
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibcheckportstate.844
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibcheckportwidth.843
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibcheckstate.836
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibcheckwidth.836
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibclearcounters.830
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibclearerrors.834
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibdatacounters.838
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibdatacounts.848
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibdiscover.850
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibfindnodesusing.830
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibhosts.831
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibidsverify.836
-rw-r--r--contrib/ofed/management/infiniband-diags/man/iblinkinfo.852
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibnetdiscover.8233
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibnodes.831
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibping.884
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibportstate.8113
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibprintca.844
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibprintrt.842
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibprintswitch.847
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibqueryerrors.863
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibroute.8119
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibrouters.831
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibstat.8110
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibstatus.841
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibswitches.831
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibswportwatch.835
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibsysstat.883
-rw-r--r--contrib/ofed/management/infiniband-diags/man/ibtracert.8112
-rw-r--r--contrib/ofed/management/infiniband-diags/man/perfquery.8124
-rw-r--r--contrib/ofed/management/infiniband-diags/man/saquery.8132
-rw-r--r--contrib/ofed/management/infiniband-diags/man/sminfo.8105
-rw-r--r--contrib/ofed/management/infiniband-diags/man/smpdump.898
-rw-r--r--contrib/ofed/management/infiniband-diags/man/smpquery.8113
-rw-r--r--contrib/ofed/management/infiniband-diags/man/vendstat.884
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/perltidy.sh60
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/IBswcountlimits.pm501
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/check_lft_balance.pl321
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/dump_lfts.sh72
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/dump_mfts.sh72
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibcheckerrors.in133
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibcheckerrs.in223
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibchecknet.in140
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibchecknode.in100
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibcheckport.in144
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibcheckportstate.in136
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibcheckportwidth.in134
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibcheckstate.in135
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibcheckwidth.in135
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibclearcounters.in107
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibclearerrors.in111
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibdatacounters.in129
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibdatacounts.in164
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibdiscover.map6
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/ibdiscover.pl86
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/ibfindnodesusing.pl231
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibhosts.in60
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/ibidsverify.pl254
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/iblinkinfo.pl327
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibnodes.in5
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/ibprintca.pl136
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/ibprintrt.pl136
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/ibprintswitch.pl135
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/ibqueryerrors.pl230
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibrouters.in60
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/ibstatus77
-rw-r--r--contrib/ofed/management/infiniband-diags/scripts/ibswitches.in79
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/ibswportwatch.pl174
-rwxr-xr-xcontrib/ofed/management/infiniband-diags/scripts/set_nodedesc.sh57
-rw-r--r--contrib/ofed/management/infiniband-diags/src/grouping.c787
-rw-r--r--contrib/ofed/management/infiniband-diags/src/ibaddr.c217
-rw-r--r--contrib/ofed/management/infiniband-diags/src/ibdiag_common.c78
-rw-r--r--contrib/ofed/management/infiniband-diags/src/ibnetdiscover.c1051
-rw-r--r--contrib/ofed/management/infiniband-diags/src/ibping.c331
-rw-r--r--contrib/ofed/management/infiniband-diags/src/ibportstate.c448
-rw-r--r--contrib/ofed/management/infiniband-diags/src/ibroute.c495
-rw-r--r--contrib/ofed/management/infiniband-diags/src/ibsendtrap.c176
-rw-r--r--contrib/ofed/management/infiniband-diags/src/ibstat.c292
-rw-r--r--contrib/ofed/management/infiniband-diags/src/ibsysstat.c354
-rw-r--r--contrib/ofed/management/infiniband-diags/src/ibtracert.c865
-rw-r--r--contrib/ofed/management/infiniband-diags/src/mcm_rereg_test.c489
-rw-r--r--contrib/ofed/management/infiniband-diags/src/perfquery.c512
-rw-r--r--contrib/ofed/management/infiniband-diags/src/saquery.c1891
-rw-r--r--contrib/ofed/management/infiniband-diags/src/sminfo.c206
-rw-r--r--contrib/ofed/management/infiniband-diags/src/smpdump.c354
-rw-r--r--contrib/ofed/management/infiniband-diags/src/smpquery.c538
-rw-r--r--contrib/ofed/management/infiniband-diags/src/vendstat.c308
-rw-r--r--contrib/ofed/management/libibcommon/AUTHORS3
-rw-r--r--contrib/ofed/management/libibcommon/COPYING384
-rw-r--r--contrib/ofed/management/libibcommon/ChangeLog21
-rw-r--r--contrib/ofed/management/libibcommon/Makefile.am32
-rwxr-xr-xcontrib/ofed/management/libibcommon/autogen.sh11
-rw-r--r--contrib/ofed/management/libibcommon/configure.in52
-rw-r--r--contrib/ofed/management/libibcommon/include/infiniband/common.h149
-rw-r--r--contrib/ofed/management/libibcommon/libibcommon.spec.in72
-rw-r--r--contrib/ofed/management/libibcommon/libibcommon.ver9
-rw-r--r--contrib/ofed/management/libibcommon/src/hash.c153
-rw-r--r--contrib/ofed/management/libibcommon/src/libibcommon.map18
-rw-r--r--contrib/ofed/management/libibcommon/src/stack.c178
-rw-r--r--contrib/ofed/management/libibcommon/src/sysfs.c294
-rw-r--r--contrib/ofed/management/libibcommon/src/time.c47
-rw-r--r--contrib/ofed/management/libibcommon/src/util.c132
-rw-r--r--contrib/ofed/management/libibmad/AUTHORS3
-rw-r--r--contrib/ofed/management/libibmad/COPYING384
-rw-r--r--contrib/ofed/management/libibmad/ChangeLog88
-rw-r--r--contrib/ofed/management/libibmad/Makefile.am34
-rwxr-xr-xcontrib/ofed/management/libibmad/autogen.sh11
-rw-r--r--contrib/ofed/management/libibmad/configure.in70
-rw-r--r--contrib/ofed/management/libibmad/include/infiniband/mad.h905
-rw-r--r--contrib/ofed/management/libibmad/libibmad.spec.in73
-rw-r--r--contrib/ofed/management/libibmad/libibmad.ver9
-rw-r--r--contrib/ofed/management/libibmad/src/dump.c782
-rw-r--r--contrib/ofed/management/libibmad/src/fields.c463
-rw-r--r--contrib/ofed/management/libibmad/src/gs.c241
-rw-r--r--contrib/ofed/management/libibmad/src/libibmad.map110
-rw-r--r--contrib/ofed/management/libibmad/src/mad.c214
-rw-r--r--contrib/ofed/management/libibmad/src/portid.c126
-rw-r--r--contrib/ofed/management/libibmad/src/register.c202
-rw-r--r--contrib/ofed/management/libibmad/src/resolve.c186
-rw-r--r--contrib/ofed/management/libibmad/src/rpc.c402
-rw-r--r--contrib/ofed/management/libibmad/src/sa.c152
-rw-r--r--contrib/ofed/management/libibmad/src/serv.c183
-rw-r--r--contrib/ofed/management/libibmad/src/smp.c123
-rw-r--r--contrib/ofed/management/libibmad/src/vendor.c99
-rw-r--r--contrib/ofed/management/libibumad/AUTHORS3
-rw-r--r--contrib/ofed/management/libibumad/COPYING384
-rw-r--r--contrib/ofed/management/libibumad/ChangeLog94
-rw-r--r--contrib/ofed/management/libibumad/Makefile.am56
-rwxr-xr-xcontrib/ofed/management/libibumad/autogen.sh11
-rw-r--r--contrib/ofed/management/libibumad/configure.in90
-rw-r--r--contrib/ofed/management/libibumad/include/infiniband/umad.h211
-rw-r--r--contrib/ofed/management/libibumad/libibumad.spec.in74
-rw-r--r--contrib/ofed/management/libibumad/libibumad.ver9
-rw-r--r--contrib/ofed/management/libibumad/man/umad_addr_dump.345
-rw-r--r--contrib/ofed/management/libibumad/man/umad_alloc.333
-rw-r--r--contrib/ofed/management/libibumad/man/umad_close_port.326
-rw-r--r--contrib/ofed/management/libibumad/man/umad_debug.329
-rw-r--r--contrib/ofed/management/libibumad/man/umad_dump.322
-rw-r--r--contrib/ofed/management/libibumad/man/umad_free.323
-rw-r--r--contrib/ofed/management/libibumad/man/umad_get_ca.365
-rw-r--r--contrib/ofed/management/libibumad/man/umad_get_ca_portguids.339
-rw-r--r--contrib/ofed/management/libibumad/man/umad_get_cas_names.337
-rw-r--r--contrib/ofed/management/libibumad/man/umad_get_fd.325
-rw-r--r--contrib/ofed/management/libibumad/man/umad_get_issm_path.338
-rw-r--r--contrib/ofed/management/libibumad/man/umad_get_mad.324
-rw-r--r--contrib/ofed/management/libibumad/man/umad_get_mad_addr.342
-rw-r--r--contrib/ofed/management/libibumad/man/umad_get_pkey.323
-rw-r--r--contrib/ofed/management/libibumad/man/umad_get_port.382
-rw-r--r--contrib/ofed/management/libibumad/man/umad_init.339
-rw-r--r--contrib/ofed/management/libibumad/man/umad_open_port.337
-rw-r--r--contrib/ofed/management/libibumad/man/umad_poll.340
-rw-r--r--contrib/ofed/management/libibumad/man/umad_recv.340
-rw-r--r--contrib/ofed/management/libibumad/man/umad_register.336
-rw-r--r--contrib/ofed/management/libibumad/man/umad_register_oui.337
-rw-r--r--contrib/ofed/management/libibumad/man/umad_send.337
-rw-r--r--contrib/ofed/management/libibumad/man/umad_set_addr.333
-rw-r--r--contrib/ofed/management/libibumad/man/umad_set_addr_net.333
-rw-r--r--contrib/ofed/management/libibumad/man/umad_set_grh.375
-rw-r--r--contrib/ofed/management/libibumad/man/umad_set_grh_net.376
-rw-r--r--contrib/ofed/management/libibumad/man/umad_set_pkey.322
-rw-r--r--contrib/ofed/management/libibumad/man/umad_size.320
-rw-r--r--contrib/ofed/management/libibumad/man/umad_status.326
-rw-r--r--contrib/ofed/management/libibumad/man/umad_unregister.330
-rw-r--r--contrib/ofed/management/libibumad/src/libibumad.map34
-rw-r--r--contrib/ofed/management/libibumad/src/umad.c1036
-rwxr-xr-xcontrib/ofed/management/make.dist144
-rw-r--r--contrib/ofed/management/opensm/AUTHORS9
-rw-r--r--contrib/ofed/management/opensm/COPYING32
-rw-r--r--contrib/ofed/management/opensm/ChangeLog14
-rw-r--r--contrib/ofed/management/opensm/INSTALL231
-rw-r--r--contrib/ofed/management/opensm/Makefile.am32
-rw-r--r--contrib/ofed/management/opensm/NEWS2
-rw-r--r--contrib/ofed/management/opensm/README25
-rwxr-xr-xcontrib/ofed/management/opensm/autogen.sh57
-rw-r--r--contrib/ofed/management/opensm/complib/ChangeLog96
-rw-r--r--contrib/ofed/management/opensm/complib/Makefile.am81
-rw-r--r--contrib/ofed/management/opensm/complib/cl_complib.c92
-rw-r--r--contrib/ofed/management/opensm/complib/cl_dispatcher.c377
-rw-r--r--contrib/ofed/management/opensm/complib/cl_event.c175
-rw-r--r--contrib/ofed/management/opensm/complib/cl_event_wheel.c573
-rw-r--r--contrib/ofed/management/opensm/complib/cl_list.c581
-rw-r--r--contrib/ofed/management/opensm/complib/cl_log.c118
-rw-r--r--contrib/ofed/management/opensm/complib/cl_map.c1636
-rw-r--r--contrib/ofed/management/opensm/complib/cl_nodenamemap.c194
-rw-r--r--contrib/ofed/management/opensm/complib/cl_pool.c671
-rw-r--r--contrib/ofed/management/opensm/complib/cl_ptr_vector.c319
-rw-r--r--contrib/ofed/management/opensm/complib/cl_spinlock.c91
-rw-r--r--contrib/ofed/management/opensm/complib/cl_statustext.c71
-rw-r--r--contrib/ofed/management/opensm/complib/cl_thread.c140
-rw-r--r--contrib/ofed/management/opensm/complib/cl_threadpool.c148
-rw-r--r--contrib/ofed/management/opensm/complib/cl_timer.c446
-rw-r--r--contrib/ofed/management/opensm/complib/cl_vector.c561
-rw-r--r--contrib/ofed/management/opensm/complib/ib_statustext.c153
-rw-r--r--contrib/ofed/management/opensm/complib/libosmcomp.map154
-rw-r--r--contrib/ofed/management/opensm/complib/libosmcomp.ver9
-rw-r--r--contrib/ofed/management/opensm/config/osmvsel.m4259
-rw-r--r--contrib/ofed/management/opensm/configure.in232
-rw-r--r--contrib/ofed/management/opensm/doc/OpenSM_PKey_Mgr.txt78
-rw-r--r--contrib/ofed/management/opensm/doc/OpenSM_RN.pdfbin0 -> 117072 bytes
-rw-r--r--contrib/ofed/management/opensm/doc/OpenSM_UM.pdfbin0 -> 307923 bytes
-rw-r--r--contrib/ofed/management/opensm/doc/QoS_management_in_OpenSM.txt492
-rw-r--r--contrib/ofed/management/opensm/doc/current-routing.txt346
-rw-r--r--contrib/ofed/management/opensm/doc/modular-routing.txt77
-rw-r--r--contrib/ofed/management/opensm/doc/opensm-coding-style.txt34
-rw-r--r--contrib/ofed/management/opensm/doc/opensm_release_notes-3.1.10.txt492
-rw-r--r--contrib/ofed/management/opensm/doc/opensm_release_notes-3.1.11.txt492
-rw-r--r--contrib/ofed/management/opensm/doc/opensm_release_notes-3.2.txt618
-rw-r--r--contrib/ofed/management/opensm/doc/opensm_release_notes_ibg2-2.0.1.txt456
-rw-r--r--contrib/ofed/management/opensm/doc/opensm_release_notes_openib-1.2.1.txt460
-rw-r--r--contrib/ofed/management/opensm/doc/opensm_release_notes_openib-2.0.5.txt486
-rw-r--r--contrib/ofed/management/opensm/doc/opensm_release_notes_openib-3.0.13.txt535
-rw-r--r--contrib/ofed/management/opensm/doc/partition-config.txt110
-rw-r--r--contrib/ofed/management/opensm/doc/perf-manager-arch.txt181
-rw-r--r--contrib/ofed/management/opensm/doc/performance-manager-HOWTO.txt153
-rw-r--r--contrib/ofed/management/opensm/doc/qos-config.txt44
-rw-r--r--contrib/ofed/management/opensm/doc/todo27
-rw-r--r--contrib/ofed/management/opensm/include/Makefile.am33
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_atomic.h196
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_atomic_osd.h104
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_byteswap.h525
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_byteswap_osd.h75
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_comppool.h585
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_debug.h594
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_debug_osd.h91
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_dispatcher.h631
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_event.h279
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_event_osd.h69
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_event_wheel.h457
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_fleximap.h907
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_list.h1292
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_log.h142
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_map.h846
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_math.h138
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_nodenamemap.h65
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_packoff.h49
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_packon.h83
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_passivelock.h323
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_pool.h561
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_ptr_vector.h825
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_qcomppool.h736
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_qlist.h1702
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_qmap.h975
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_qpool.h606
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_spinlock.h272
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_spinlock_osd.h61
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_thread.h356
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_thread_osd.h68
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_threadpool.h248
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_timer.h349
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_timer_osd.h81
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_types.h472
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_types_osd.h88
-rw-r--r--contrib/ofed/management/opensm/include/complib/cl_vector.h945
-rw-r--r--contrib/ofed/management/opensm/include/iba/ib_cm_types.h203
-rw-r--r--contrib/ofed/management/opensm/include/iba/ib_types.h10720
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_attrib_req.h108
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_base.h898
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_config.h65
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_config.h.in64
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_console.h51
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_console_io.h90
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_db.h427
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_db_pack.h243
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_errors.h176
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_event_plugin.h192
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_helper.h550
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_inform.h238
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_lid_mgr.h289
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_log.h482
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_mad_pool.h372
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_madw.h1115
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_mcast_tbl.h461
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_mcm_info.h136
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_mcm_port.h158
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_msgdef.h167
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_mtree.h274
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_multicast.h503
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_node.h679
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_opensm.h527
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_partition.h273
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_path.h250
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_perfmgr.h250
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_perfmgr_db.h209
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_pkey.h636
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_pkey_mgr.h80
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_port.h1591
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_port_profile.h207
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_prefix_route.h63
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_qos_policy.h204
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_remote_sm.h198
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_router.h217
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_sa.h496
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_sa_mad_ctrl.h338
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_service.h194
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_sm.h798
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_sm_mad_ctrl.h323
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_stats.h184
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_subnet.h1106
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_switch.h1152
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_ucast_cache.h240
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_ucast_mgr.h308
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_version.h51
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_version.h.in51
-rw-r--r--contrib/ofed/management/opensm/include/opensm/osm_vl15intf.h367
-rw-r--r--contrib/ofed/management/opensm/include/opensm/st.h102
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_mtl_bind.h136
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_pkt_randomizer.h224
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_ts_useraccess.h52
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_umadt.h137
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor.h71
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_al.h348
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_api.h487
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_ibumad.h181
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx.h96
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_defs.h103
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_dispatcher.h70
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_hca.h64
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_inout.h76
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_rmpp_ctx.h289
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_sar.h116
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_sender.h128
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_svc.h201
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_transport.h95
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_transport_anafa.h69
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mlx_txn.h380
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mtl.h348
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mtl_hca_guid.h195
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_mtl_transaction_mgr.h299
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_sa_api.h866
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_test.h123
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_ts.h410
-rw-r--r--contrib/ofed/management/opensm/include/vendor/osm_vendor_umadt.h130
-rw-r--r--contrib/ofed/management/opensm/libvendor/ChangeLog64
-rw-r--r--contrib/ofed/management/opensm/libvendor/Makefile.am86
-rw-r--r--contrib/ofed/management/opensm/libvendor/libosmvendor.map20
-rw-r--r--contrib/ofed/management/opensm/libvendor/libosmvendor.ver9
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_pkt_randomizer.c329
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_al.c1320
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_ibumad.c1154
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_ibumad_sa.c736
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx.c770
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_anafa.c753
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_dispatcher.c710
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca.c524
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca_anafa.c194
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca_pfs.c751
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_hca_sim.c864
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_ibmgt.c783
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_rmpp_ctx.c361
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sa.c834
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sar.c154
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sender.c390
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_sim.c439
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_ts.c505
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_ts_anafa.c416
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mlx_txn.c675
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mtl.c1105
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mtl_hca_guid.c635
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_mtl_transaction_mgr.c546
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_test.c282
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_ts.c904
-rw-r--r--contrib/ofed/management/opensm/libvendor/osm_vendor_umadt.c1117
-rw-r--r--contrib/ofed/management/opensm/man/opensm.81012
-rw-r--r--contrib/ofed/management/opensm/man/opensm.8.in1012
-rw-r--r--contrib/ofed/management/opensm/man/osmtest.8190
-rw-r--r--contrib/ofed/management/opensm/opensm.spec.in146
-rw-r--r--contrib/ofed/management/opensm/opensm/ChangeLog115
-rw-r--r--contrib/ofed/management/opensm/opensm/Makefile.am131
-rw-r--r--contrib/ofed/management/opensm/opensm/libopensm.map59
-rw-r--r--contrib/ofed/management/opensm/opensm/libopensm.ver9
-rw-r--r--contrib/ofed/management/opensm/opensm/main.c1027
-rwxr-xr-xcontrib/ofed/management/opensm/opensm/osm_check282
-rwxr-xr-xcontrib/ofed/management/opensm/opensm/osm_check_n_fix517
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_console.c1327
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_console_io.c254
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_db_files.c723
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_db_pack.c157
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_drop_mgr.c516
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_dump.c642
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_event_plugin.c150
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_helper.c2334
-rwxr-xr-xcontrib/ofed/management/opensm/opensm/osm_indent56
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_inform.c616
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_lid_mgr.c1321
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_lin_fwd_rcv.c101
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_link_mgr.c416
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_log.c337
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_mad_pool.c188
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_mcast_fwd_rcv.c121
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_mcast_mgr.c1267
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_mcast_tbl.c284
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_mcm_info.c70
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_mcm_port.c76
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_mtree.c125
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_multicast.c302
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_node.c312
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_node_desc_rcv.c128
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_node_info_rcv.c849
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_opensm.c497
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_perfmgr.c1311
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_perfmgr_db.c807
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_pkey.c467
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_pkey_mgr.c528
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_pkey_rcv.c145
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_port.c780
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_port_info_rcv.c687
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_prtn.c392
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_prtn_config.c462
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_qos.c413
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_qos_parser_l.l394
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_qos_parser_y.y3063
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_qos_policy.c1091
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_remote_sm.c79
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_req.c280
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_resp.c157
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_router.c75
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa.c1123
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_class_port_info.c213
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_guidinfo_record.c362
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_informinfo.c626
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_lft_record.c246
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_link_record.c505
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_mad_ctrl.c592
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_mcmember_record.c1735
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_mft_record.c280
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_multipath_record.c1536
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_node_record.c355
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_path_record.c1813
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_pkey_record.c341
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_portinfo_record.c592
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_service_record.c842
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_slvl_record.c313
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_sminfo_record.c331
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_sw_info_record.c273
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sa_vlarb_record.c330
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_service.c166
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_slvl_map_rcv.c152
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sm.c655
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sm_mad_ctrl.c874
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sm_state_mgr.c551
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sminfo_rcv.c604
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_state_mgr.c1396
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_subnet.c1719
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_sw_info_rcv.c506
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_switch.c667
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_trap_rcv.c714
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_ucast_cache.c1095
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_ucast_file.c396
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_ucast_ftree.c3669
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_ucast_lash.c1356
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_ucast_mgr.c903
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_ucast_updn.c686
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_vl15intf.c386
-rw-r--r--contrib/ofed/management/opensm/opensm/osm_vl_arb_rcv.c154
-rw-r--r--contrib/ofed/management/opensm/opensm/st.c588
-rw-r--r--contrib/ofed/management/opensm/osmeventplugin/Makefile.am34
-rw-r--r--contrib/ofed/management/opensm/osmeventplugin/libosmeventplugin.map5
-rw-r--r--contrib/ofed/management/opensm/osmeventplugin/libosmeventplugin.ver9
-rw-r--r--contrib/ofed/management/opensm/osmeventplugin/src/osmeventplugin.c188
-rw-r--r--contrib/ofed/management/opensm/osmtest/Makefile.am23
-rw-r--r--contrib/ofed/management/opensm/osmtest/include/osmt_inform.h78
-rw-r--r--contrib/ofed/management/opensm/osmtest/include/osmt_mtl_regular_qp.h162
-rw-r--r--contrib/ofed/management/opensm/osmtest/include/osmtest.h510
-rw-r--r--contrib/ofed/management/opensm/osmtest/include/osmtest_base.h67
-rw-r--r--contrib/ofed/management/opensm/osmtest/include/osmtest_subnet.h326
-rw-r--r--contrib/ofed/management/opensm/osmtest/main.c623
-rw-r--r--contrib/ofed/management/opensm/osmtest/osmt_inform.c767
-rw-r--r--contrib/ofed/management/opensm/osmtest/osmt_mtl_regular_qp.c469
-rw-r--r--contrib/ofed/management/opensm/osmtest/osmt_multicast.c2707
-rw-r--r--contrib/ofed/management/opensm/osmtest/osmt_service.c1616
-rw-r--r--contrib/ofed/management/opensm/osmtest/osmt_slvl_vl_arb.c528
-rw-r--r--contrib/ofed/management/opensm/osmtest/osmtest.c7403
-rw-r--r--contrib/ofed/management/opensm/scripts/opensm.init.in133
-rw-r--r--contrib/ofed/management/opensm/scripts/opensm.logrotate7
-rw-r--r--contrib/ofed/management/opensm/scripts/opensm.sysconfig2
-rwxr-xr-xcontrib/ofed/management/opensm/scripts/redhat-opensm.init.in292
-rwxr-xr-xcontrib/ofed/management/opensm/scripts/sldd.sh.in246
512 files changed, 186986 insertions, 0 deletions
diff --git a/contrib/ofed/management/AUTHORS b/contrib/ofed/management/AUTHORS
new file mode 100644
index 0000000..d09c13f
--- /dev/null
+++ b/contrib/ofed/management/AUTHORS
@@ -0,0 +1,3 @@
+Shahar Frank <shahar@voltaire.com>
+Hal Rosenstock <halr@voltaire.com>
+Sasha Khapyorsky <sashak@voltaire.com>
diff --git a/contrib/ofed/management/COPYING b/contrib/ofed/management/COPYING
new file mode 100644
index 0000000..1b1ca1d
--- /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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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 0000000..e69de29
--- /dev/null
+++ b/contrib/ofed/management/ChangeLog
diff --git a/contrib/ofed/management/INSTALL b/contrib/ofed/management/INSTALL
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/contrib/ofed/management/INSTALL
diff --git a/contrib/ofed/management/Makefile b/contrib/ofed/management/Makefile
new file mode 100644
index 0000000..863c3aa
--- /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 0000000..e69de29
--- /dev/null
+++ b/contrib/ofed/management/NEWS
diff --git a/contrib/ofed/management/README b/contrib/ofed/management/README
new file mode 100644
index 0000000..c6efd9f
--- /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 <portguid_in_hex>".
+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 0000000..f0f15cb
--- /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 0000000..8ef2590
--- /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 <smlid> use 'smlid' as the target lid for SA queries.
+
+ # Local umad parameters:
+ -C <ca_name> use the specified ca_name.
+ -P <ca_port> use the specified ca_port.
+ -t <timeout_ms> 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)] <ca_name> [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] <switch_addr> [<startlid> [<endlid>]]]
+
+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] <src-addr> <dest-addr>
+
+Non standard flags:
+ -n simple format; don't show additional information.
+ -m <mlid> 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> <dest_addr> [op_params]
+
+Current supported operations and their parameters:
+ nodeinfo <addr>
+ nodedesc <addr>
+ portinfo <addr> [<portnum>] # default port is zero
+ switchinfo <addr>
+ pkeys <addr> [<portnum>]
+ sl2vl <addr> [<portnum>]
+ vlarb <addr> [<portnum>]
+
+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] <dest_addr> <attr> [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] [<dest_addr>]
+
+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] <sm_lid|sm_dr_path> [sminfo_modifier]
+
+Non standard flags:
+ -s <state> # use the specified state in sminfo mad
+ -p <priority> # use the specified priority in sminfo mad
+ -a <activity> # 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] [<lid|guid> [[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] <dest lid|guid>
+
+Non standard flags:
+ -c <count> stop after count packets
+ -f flood destination: send packets back to back w/o delay
+ -o <oui> 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] [<topology-filename>]
+
+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] [<topology-file>]
+
+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] [<topology-file>]
+
+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] [<topology-file>]
+
+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] <lid|guid> <port_number>
+
+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] <lid|guid>
+
+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 <file> option.
+
+Syntax:
+ibcheckerrs [-h] [-G] [-t <threshold_file>] [-s(how_thresholds)] <lid|guid> [<port>]
+
+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] <dest dr_path|lid|guid>
+<portnum> [<op>]
+ 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] [<topology-file>]
+
+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] <lid|guid> <port>
+
+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] [<topology-file>]
+
+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] <lid|guid> <port_number>
+
+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] [<topology-file>]
+
+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:
+<nodeGUID>|port|"Text for node"|<NodeDescription from ibnetdiscover format>
+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:
+<LocalPort>|<LocalNodeGUID>|<RemotePort>|<RemoteNodeGUID>
+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 [<topology-file>]
+
+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] [<topology-file>]
+
+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] [<topology-file>]
+
+Dependencies:
+ibnetdiscover, ibnetdiscover format, perfquery
+
+28. saquery
+
+Description:
+Issue some SA queries.
+
+Syntax:
+Usage: saquery [-h -d -P -N -L -G -s -g][<name>]
+ 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] <dest lid|guid> [<op>]
+
+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 <oui> 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 0000000..c86000c
--- /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 <timeout in msec>] \
+ [-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 0000000..42a61d4
--- /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 0000000..76809f7
--- /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 0000000..bd1dbd8
--- /dev/null
+++ b/contrib/ofed/management/gen_chlog.sh
@@ -0,0 +1,74 @@
+#!/bin/sh
+
+usage()
+{
+ echo "Usage: $0 [--spec] <target>"
+ 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 0000000..93882d4
--- /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 <target>"
+ 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 0000000..a017728
--- /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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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 0000000..6add52a
--- /dev/null
+++ b/contrib/ofed/management/infiniband-diags/ChangeLog
@@ -0,0 +1,470 @@
+2007-08-09 Ira Weiny <weiny2@llnl.gov>
+
+ * 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 <halr@voltaire.com>
+
+ * 1.3.1 release of infiniband-diags
+
+2007-06-20 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * man/ibaddr.8: Improve description
+
+2007-06-04 Hal Rosenstock <halr@voltaire.com>
+
+ * include/ibnetdiscover.h, src/ibnetdiscover.c,
+ man/ibnetdiscover.8: Add link width and speed to topology
+ file output
+
+2007-06-02 Hal Rosenstock <halr@voltaire.com>
+
+ * man/ibnetdiscover.8: Add topology file format section
+
+2007-06-01 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * scripts/ibprintca.pl: Add support for routers
+
+2007-05-23 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * src/grouping.c: Eliminate conditional compilation
+ based on WORDSIZE
+
+2007-05-08 Hal Rosenstock <halr@voltaire.com>
+
+ * src/ibnetdiscover.c: Bumped build version
+
+ * include/grouping.h, src/grouping.c: Added support
+ for ISR2012 and ISR2004
+
+2007-04-27 Ira K. Weiny <weiny2@llnl.gov>
+
+ * 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 <chu11@llnl.gov>
+
+ * 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 <halr@voltaire.com>
+
+ * src/saquery.c, man/saquery.8: Add support for isSMdisabled
+ into -s query
+
+2007-04-02 Albert L. Chu <chu11@llnl.gov>
+
+ * 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 <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * 1.3.0 release of openib-diags
+
+2007-03-21 Albert L. Chu <chu11@llnl.gov>
+
+ * scripts/IBswcountlimits.pm: Add some extra debug information
+
+2007-03-21 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * src/ibnetdiscover.c: Chassis 0 is not a chassis
+ Caused Cisco SFS7000 to be reported as a chassis
+
+2007-03-15 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <dotanb@mellanox.co.il>
+
+ * src/smpquery.c: Add support to query the GUIDInfo
+ table
+
+2007-03-12 Ira K. Weiny <weiny2@llnl.gov>
+
+ * configure.in, diags.spec.in, ibdiag_common.c:
+ Allow user to specify a default switch map file
+
+2007-03-09 Hal Rosenstock <halr@voltaire.com>
+
+ * 1.2.5 release of openib-diags
+
+2007-03-09 Albert L. Chu <chu11@llnl.gov>
+
+ * configure.in, scripts/ibcheck*, scripts/ibclear*,
+ scripts/ibhosts, scripts/ibnodes, scripts/ibswitches:
+ autoconf support for default pathname in scripts
+
+2007-03-05 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * include/ibdiag_common.h, src/ibdiag_common.c,
+ src/saquery.c: Clean gcc-4.1 warnings
+
+2007-03-03 Hal Rosenstock <halr@voltaire.com>
+
+ * 1.2.4 release of openib-diags
+
+2007-03-02 Ira K. Weiny <weiny2@llnl.gov>
+
+ * 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 <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * 1.2.2 release of openib-diags
+
+ * scripts/ibswitches, scripts/ibhosts: Removed extra quotes
+ around display of NodeDescription
+
+2007-02-15 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * 1.2.0 release of openib-diags
+
+2007-02-02 Ira Weiny <weiny2@llnl.gov>
+
+ * scripts/ibcheckerrors, scripts/ibcheckerrs: Added
+ brief option
+ * man/ibcheckerrors.8, man/ibcheckerrs.8: Updated
+ man pages for brief option
+
+2007-02-02 Hal Rosenstock <halr@voltaire.com>
+
+ * src/ibportstate.c, src/sminfo.c, src/smpquery.c:
+ Update build version tags
+
+2007-02-01 Hal Rosenstock <halr@voltaire.com>
+
+ * src/saquery.c: Add build version option
+
+2007-02-01 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <weiny2@llnl.gov>
+
+ * 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 <weiny2@llnl.gov>
+
+ * 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 <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * src/ibnetdiscover.c: Add non Voltaire chassis listing back
+ into dump_topology
+
+2007-01-29 Ira Weiny <weiny2@llnl.gov>
+
+ * 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 <weiny2@llnl.gov>
+
+ * include/grouping.h, src/grouping.c: Change group_nodes API
+ signature to return point to ChassisList rather than void
+
+2007-01-27 Ira Weiny <weiny2@llnl.gov>
+
+ * 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 <halr@voltaire.com>
+
+ * src/ibnetdiscover.c: Cosmetic change to some router strings
+
+2007-01-24 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * src/ibnetdiscover.c: Minor clean_nodedesc simplification
+
+2007-01-18 Hal Rosenstock <halr@voltaire.com>
+
+ * src/perfquery.c: Minor code reorder
+
+2007-01-17 Ira Weiny <weiny2@llnl.gov>
+
+ * scripts/iblinkinfo.pl: Add better error handling
+
+ * src/saquery.c: Add timeout option to command line
+
+2007-01-16 Hal Rosenstock <halr@voltaire.com>
+
+ * man/perfquery.8: Removed unneeded DR description in common options
+
+2007-01-13 Hal Rosenstock <halr@voltaire.com>
+
+ * scripts/dump_mfts.sh, man/dump_mfts.8: Add dump_mfts similar
+ to dump_lfts
+
+2007-01-12 Hal Rosenstock <halr@voltaire.com>
+
+ * man/dump_lfts.8: Minor changes based on existence of dump_mfts
+
+2007-01-04 Hal Rosenstock <halr@voltaire.com>
+
+ * scripts/iblinkspeed.pl, man/iblinkspeed.8: Removed as no
+ longer needed
+
+2007-01-03 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * src/ibnetdiscover.c: Discover improvements
+ (memory leaks, ports moving, etc.)
+
+2007-01-02 Ira Weiny <weiny2@llnl.gov>
+
+ * scripts/iblinkinfo.pl: Convert iblinkspeed.pl into
+ iblinkinfo.pl and add additional capabilities
+
+2006-12-28 Hal Rosenstock <halr@voltaire.com>
+
+ * src/ibtracert.c: Add 0x in front of GUID printing
+
+2006-12-28 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * src/saquery.c, man/saquery.8: Add support for
+ querying ServiceRecords
+
+2006-11-21 Hal Rosenstock <halr@voltaire.com>
+
+ * src/perfquery.c: Add support for PerfMgt ClassPortInfo:
+ CapabilityMask IsExtendedWidthSupported IBA 1.2 erratum
+
+2006-11-20 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * src/ibnetdiscover.c, src/ibtracert.c: Fix various
+ uses of printf() style functions
+
+2006-10-20 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <sashak@voltaire.com>
+
+ * src/ibroute.c: Fix double calculated block value.
+
+2006-10-16 Hal Rosenstock <halr@voltaire.com>
+
+ * src/ibnetdiscover.c, src/ibtracert.c: IB router support.
+
+2006-10-09 Ira Weiny <weiny2@llnl.gov>
+
+ * 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 <halr@voltaire.com>
+
+ * 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 <dotanb@mellanox.co.il>
+
+ * 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 0000000..c22ba5e
--- /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 0000000..c251726
--- /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 <smlid> use 'smlid' as the target lid for SA queries.
+
+ # Local umad parameters:
+ -C <ca_name> use the specified ca_name.
+ -P <ca_port> use the specified ca_port.
+ -t <timeout_ms> 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)] <ca_name> [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] <switch_addr> [<startlid> [<endlid>]]]
+
+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] <src-addr> <dest-addr>
+
+Non standard flags:
+ -n simple format; don't show additional information.
+ -m <mlid> 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> <dest_addr> [op_params]
+
+Current supported operations and their parameters:
+ nodeinfo <addr>
+ nodedesc <addr>
+ portinfo <addr> [<portnum>] # default port is zero
+ switchinfo <addr>
+ pkeys <addr> [<portnum>]
+ sl2vl <addr> [<portnum>]
+ vlarb <addr> [<portnum>]
+
+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] <dest_addr> <attr> [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] [<dest_addr>]
+
+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] <sm_lid|sm_dr_path> [sminfo_modifier]
+
+Non standard flags:
+ -s <state> # use the specified state in sminfo mad
+ -p <priority> # use the specified priority in sminfo mad
+ -a <activity> # 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] [<lid|guid> [[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] <dest lid|guid>
+
+Non standard flags:
+ -c <count> stop after count packets
+ -f flood destination: send packets back to back w/o delay
+ -o <oui> 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] [<topology-filename>]
+
+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] [<topology-file>]
+
+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] [<topology-file>]
+
+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] [<topology-file>]
+
+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] <lid|guid> <port_number>
+
+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] <lid|guid>
+
+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 <file> option.
+
+Syntax:
+ibcheckerrs [-h] [-G] [-t <threshold_file>] [-s(how_thresholds)] <lid|guid> [<port>]
+
+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] <dest dr_path|lid|guid>
+<portnum> [<op>]
+ 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] [<topology-file>]
+
+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] <lid|guid> <port>
+
+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] [<topology-file>]
+
+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] <lid|guid> <port_number>
+
+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] [<topology-file>]
+
+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:
+<nodeGUID>|port|"Text for node"|<NodeDescription from ibnetdiscover format>
+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:
+<LocalPort>|<LocalNodeGUID>|<RemotePort>|<RemoteNodeGUID>
+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 [<topology-file>]
+
+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] [<topology-file>]
+
+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] [<topology-file>]
+
+Dependencies:
+ibnetdiscover, ibnetdiscover format, perfquery
+
+28. saquery
+
+Description:
+Issue some SA queries.
+
+Syntax:
+Usage: saquery [-h -d -P -N -L -G -s -g][<name>]
+ 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] <dest lid|guid> [<op>]
+
+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 <oui> 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 0000000..4827884
--- /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 0000000..d8524f4
--- /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([<infiniband/common.h> not found. diags require libibcommon.])
+)
+AC_CHECK_HEADER(infiniband/umad.h, [],
+ AC_MSG_ERROR([<infiniband/umad.h> not found. diags require libibumad.])
+)
+AC_CHECK_HEADER(infiniband/mad.h, [],
+ AC_MSG_ERROR([<infiniband/mad.h> 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 0000000..e54efef
--- /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 0000000..39e09d7
--- /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 <stdio.h>
+#include <inttypes.h>
+
+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 <ibdiag_version.h>
+
+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 0000000..da9ed51
--- /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 0000000..62430c5
--- /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 0000000..0226615
--- /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 0000000..9c8c0c4
--- /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 <chu11@llnl.gov> - 1.3.5
+- Add check_lft_balance script.
+
+* Wed Oct 31 2007 Ira Weiny <weiny2@llnl.gov> - 1.3.2
+- Change switch-map option to node-name-map
+
+* Thu Aug 9 2007 Ira Weiny <weiny2@llnl.gov> - 1.3.1
+- Change set_mthca_nodedesc.sh to set_nodedesc.sh
+
+* Tue Jul 10 2007 Hal Rosenstock <halr@voltaire.com> - 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 <halr@voltaire.com> - 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 <halr@voltaire.com> - 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 <halr@voltaire.com> - 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 <halr@voltaire.com> - 1.2.3
+- OpenFabrics 1.2.3 release
+- Fixed saquery timeout handling
+
+* Tue Feb 27 2007 Hal Rosenstock <halr@voltaire.com> - 1.2.2
+- OpenFabrics 1.2.2 release
+- Minor changes to ibswitches and ibhosts output
+
+* Thu Feb 14 2007 Hal Rosenstock <halr@voltaire.com> - 1.2.1
+- OpenFabrics 1.2.1 release
+- Initial release of vendstat tool
+
+* Fri Feb 2 2007 Hal Rosenstock <halr@voltaire.com> - 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 <halr@voltaire.com> - 1.1.0
+- OpenFabrics 1.1 release
+
+* Wed Sep 13 2006 Hal Rosenstock <halr@voltaire.com> - 1.1.0-rc5
+- OpenFabrics 1.1-rc5 release
+
+* Wed Sep 6 2006 Hal Rosenstock <halr@voltaire.com> - 1.1.0-rc4
+- OpenFabrics 1.1-rc4 release
+
+* Wed Aug 23 2006 Hal Rosenstock <halr@voltaire.com> - 1.1.0-rc3
+- OpenFabrics 1.1-rc3 release
+
+* Mon Aug 14 2006 Hal Rosenstock <halr@voltaire.com> - 1.1.0-rc2
+- OpenFabrics 1.1-rc2 release
+- Added ibsysstat man page
+
+* Wed Jul 26 2006 Hal Rosenstock <halr@voltaire.com> - 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 <halr@voltaire.com> - 1.0-1
+- OpenFabrics 1.0 release
+
+* Tue May 30 2006 Hal Rosenstock <halr@voltaire.com> - 1.0.0-rc6
+- Maintenance release
+
+* Fri May 12 2006 Hal Rosenstock <halr@voltaire.com> - 1.0.0-rc5
+- Maintenance release
+
+* Thu Apr 27 2006 Hal Rosenstock <halr@voltaire.com> - 1.0.0-rc4
+- Maintenance release
+- Note rc3 skipped to sync with OFED
+
+* Mon Apr 10 2006 Hal Rosenstock <halr@voltaire.com> - 1.0.0-rc2
+- Maintenance release
+
+* Mon Feb 27 2006 Hal Rosenstock <halr@voltaire.com> - 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 0000000..3eeca0dd
--- /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 0000000..4498260
--- /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 <ca_name>
+use the specified ca_name.
+.TP
+\fB\-P\fR <ca_port>
+use the specified ca_port.
+.TP
+\fB\-t\fR <timeout_ms>
+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 0000000..885301e
--- /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 <ca_name>
+use the specified ca_name.
+.TP
+\fB\-P\fR <ca_port>
+use the specified ca_port.
+.TP
+\fB\-t\fR <timeout_ms>
+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 0000000..622c6f9
--- /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)] [<lid | dr_path | guid>]
+
+.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 <smlid> use 'smlid' as the target lid for SM/SA queries.
+
+# Other common flags:
+.PP
+\-C <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..7c2467f
--- /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] [<topology-file> | \-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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..f8aa848
--- /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 <threshold_file>] [\-s(how_thresholds)]
+[\-N | \-nocolor] [\-C ca_name] [\-P ca_port] [\-t(imeout) timeout_ms]
+<lid|guid> <port>
+
+
+.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 <file> 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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..f907823
--- /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] [<topology-file> | \-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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..3d65d8a
--- /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] <lid|guid>
+
+.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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..f01095b
--- /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] <lid|guid> <port>
+
+.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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..8d7f38b
--- /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] <lid|guid> <port>
+
+.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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..85c06fc
--- /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] <lid|guid> <port>
+
+.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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..89daeb8
--- /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] [<topology-file> | \-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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..1414fb2
--- /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] [<topology-file> | \-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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..1fca7bd
--- /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] [<topology-file> | \-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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..7692c64
--- /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] [<topology-file> | \-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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..60fec8f
--- /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] [<topology-file> | \-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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..d1b31e3
--- /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] <lid|guid> [<port>]
+
+.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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..5e1e019
--- /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:
+
+<nodeGUID>|port|"Text for node"|<NodeDescription from ibnetdiscover format>
+
+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:
+
+<LocalPort>|<LocalNodeGUID>|<RemotePort>|<RemoteNodeGUID>
+
+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 0000000..d5e3e68
--- /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] <switch_guid|switch_name> <port>
+
+.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 0000000..db3c8ce
--- /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] [<topology-file> | \-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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..f42fd44
--- /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 0000000..ebb0394
--- /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 <ca_name> -P <ca_port> -v <lt,hoq,vlstall> -S <guid> -D <direct_route>]
+
+.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 <guid>\fR
+Output only the switch specified by <guid> (hex format)
+.TP
+\fB\-D <direct_route>\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 <lt,hoq,vlstall>\fR
+Verify additional switch settings (<LifeTime>,<HoqLife>,<VLStallCount>)
+.TP
+\fB\-c\fR
+Print port capabilities (enabled and supported values)
+.TP
+\fB\-C <ca_name>\fR use the specified ca_name for the search.
+.TP
+\fB\-P <ca_port>\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 0000000..958efa9
--- /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 <node-name-map>] [\-p(orts)] [\-h(elp)] [<topology-file>]
+
+.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 <node-name-map>
+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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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
+<guid> "<name>"
+
+.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 0000000..901665d
--- /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] [<topology-file> | \-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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..c25fc8d
--- /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)] <dest lid | guid>
+
+.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 <smlid> use 'smlid' as the target lid for SM/SA queries.
+
+# Other common flags:
+.PP
+\-C <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..0306f29
--- /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)] <dest dr_path|lid|guid> <portnum> [<op>]
+
+.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 <smlid> use 'smlid' as the target lid for SM/SA queries.
+
+# Other common flags:
+.PP
+\-C <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..ae304f7
--- /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 <ca_name> -P <ca_port>] [<ca_guid|node_name>]
+
+.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 <ca_name>\fR use the specified ca_name for the search.
+.TP
+\fB\-P <ca_port>\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 0000000..4929586
--- /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 <ca_name> -P <ca_port>] [<rt_guid|node_name>]
+
+.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 <ca_name>\fR use the specified ca_name for the search.
+.TP
+\fB\-P <ca_port>\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 0000000..11e0a87
--- /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 <ca_name> -P <ca_port>] [<switch_guid|switch_name>]
+
+.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 <ca_name>\fR use the specified ca_name for the search.
+.TP
+\fB\-P <ca_port>\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 0000000..5c7eb17
--- /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 <ca_name> -P <ca_port> -s <err1,err2,...> -S <switch_guid> -D <direct_route> -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 <err1,err2,...>\fR
+Suppress the errors listed in the comma separated list provided.
+.TP
+\fB\-S <switch_guid>\fR
+Report results only for the switch specified. (hex format)
+.TP
+\fB\-D <direct_route>\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 <ca_name>\fR use the specified ca_name for the search.
+.TP
+\fB\-P <ca_port>\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 0000000..9f28477
--- /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)] [<dest dr_path|lid|guid> [<startlid> [<endlid>]]]
+
+.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 <smlid> use 'smlid' as the target lid for SM/SA queries.
+
+# Other common flags:
+.PP
+\-C <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..9c3ef68
--- /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] [<topology-file> | \-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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..b607d83
--- /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] <ca_name> [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 <smlid> use 'smlid' as the target lid for SM/SA queries.
+
+# Other common flags:
+.PP
+\-C <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..c4b3831
--- /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 0000000..3bd9904
--- /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] [<topology-file> | \-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 <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..72501ab
--- /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 <pause_time> -v -n <cycles> -G] <guid|lid> <port>
+
+.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 <pause_time>\fR
+Specify a pause time (polling interval) other than the default.
+.TP
+\fB\-v\fR
+Be verbose.
+.TP
+\fB\-n <cycles>\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 0000000..2f2c69f
--- /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)] <dest lid | guid> [<op>]
+
+.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 <smlid> use 'smlid' as the target lid for SM/SA queries.
+
+# Other common flags:
+.PP
+\-C <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..1b48572
--- /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 <node-name-map>] [\-h(elp)] [<dest dr_path|lid|guid> [<startlid> [<endlid>]]]
+
+.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 <node-name-map>
+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 <smlid> use 'smlid' as the target lid for SM/SA queries.
+
+# Other common flags:
+.PP
+\-C <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..716d6ff
--- /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)] [<lid|guid> [[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 <smlid> use 'smlid' as the target lid for SM/SA queries.
+
+# Other common flags:
+.PP
+\-C <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..82a5fed
--- /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) <msec>]
+[\-\-src\-to\-dst <src:dst>]
+[\-\-sgid\-to\-dgid <sgid\-dgid>]
+[\-\-node\-name\-map <node\-name\-map>]
+[<name> | <lid> | <guid>]
+
+.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 <src:dst>
+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 <ca_name>
+use the specified ca_name.
+.TP
+\fB\-P\fR <ca_port>
+use the specified ca_port.
+.TP
+\fB\-\-smkey\fR <val>
+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 <msec>
+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 <node-name-map>
+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 0000000..6c57362
--- /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 <smlid> use 'smlid' as the target lid for SM/SA queries.
+
+# Other common flags:
+.PP
+\-C <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..2a08753
--- /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)] <dlid|dr_path> <attr> [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 <smlid> use 'smlid' as the target lid for SM/SA queries.
+
+# Other common flags:
+.PP
+\-C <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..5b719c4
--- /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> <dest dr_path|lid|guid> [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 <addr>
+ nodedesc <addr>
+ portinfo <addr> [<portnum>] # default port is zero
+ switchinfo <addr>
+ pkeys <addr> [<portnum>]
+ sl2vl <addr> [<portnum>]
+ vlarb <addr> [<portnum>]
+ guids <addr>
+
+.TP
+\fB\-\-node\-name\-map\fR <node-name-map>
+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 <smlid> use 'smlid' as the target lid for SM/SA queries.
+
+# Other common flags:
+.PP
+\-C <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..e32650a
--- /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)] <lid|guid>
+
+.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 <smlid> use 'smlid' as the target lid for SM/SA queries.
+
+# Other common flags:
+.PP
+\-C <ca_name> use the specified ca_name.
+.PP
+\-P <ca_port> use the specified ca_port.
+.PP
+\-t <timeout_ms> 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 0000000..bc5f0de
--- /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 <weiny2@llnl.gov>.
+#
+# This software is available to you under a choice of one of two
+# licenses. You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, available from the file
+# COPYING in the main directory of this source tree, or the
+# OpenIB.org BSD license below:
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# - Redistributions of source code must retain the above
+# copyright notice, this list of conditions and the following
+# disclaimer.
+#
+# - Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials
+# provided with the distribution.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION 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 0000000..6623b8b
--- /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 <weiny2@llnl.gov>.
+# 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 = <IBNET_TOPO>) {
+ 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 0000000..cd4950f
--- /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 <weiny2@llnl.gov>
+# Jim Garlick <garlick@llnl.gov>
+# Albert Chu <chu11@llnl.gov>
+#
+# This software is available to you under a choice of one of two
+# licenses. You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, available from the file
+# COPYING in the main directory of this source tree, or the
+# OpenIB.org BSD license below:
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# - Redistributions of source code must retain the above
+# copyright notice, this list of conditions and the following
+# disclaimer.
+#
+# - Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials
+# provided with the distribution.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION 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 = <FH>;
+
+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 0000000..ebca705
--- /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 0000000..39fc5fb
--- /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 0000000..a45bd63
--- /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]"\
+ "[<topology-file> | -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 0000000..305379a
--- /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 <threshold_file>]" \
+ "[-s(how_thresholds)] [-N \| -nocolor] [-C ca_name] [-P ca_port]" \
+ "[-t(imeout) timeout_ms] <lid|guid> [<port>]"
+ 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 0000000..6447835
--- /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]" \
+ "[<topology-file> | -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 0000000..5eea7b5
--- /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] <lid|guid>"
+ 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 0000000..fa5e81e
--- /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] <lid|guid> <port>"
+ 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 0000000..dc4fb14
--- /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] <lid|guid> <port>"
+ 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 0000000..32c5c5e
--- /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] <lid|guid> <port>"
+ 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 0000000..63551d5
--- /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]" \
+ "[<topology-file> | -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 0000000..6b723c5
--- /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]" \
+ "[<topology-file> \| -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 0000000..86a5528
--- /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] [<topology-file>" \
+ "| -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 0000000..3dfb96b
--- /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] [<topology-file>" \
+ "| -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 0000000..5967406
--- /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]" \
+ "[<topology-file> \| -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 0000000..3dbc56a
--- /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] <lid|guid>" \
+ "[<port>]"
+ 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 0000000..58c69da
--- /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 0000000..8606919
--- /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 (<MAP>) {
+ ($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 (<TOPO>) {
+ $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 (<STDIN>) {
+ ($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 0000000..a2102c7
--- /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 <weiny2@llnl.gov>
+# Jim Garlick <garlick@llnl.gov>
+# Albert Chu <chu11@llnl.gov>
+#
+# This software is available to you under a choice of one of two
+# licenses. You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, available from the file
+# COPYING in the main directory of this source tree, or the
+# OpenIB.org BSD license below:
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# - Redistributions of source code must retain the above
+# copyright notice, this list of conditions and the following
+# disclaimer.
+#
+# - Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials
+# provided with the distribution.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION 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 <ca_name> -P <ca_port>] <switch_guid|switch_name> <port>\n";
+ print " find a list of nodes which are routed through switch:port\n";
+ print " -R Recalculate ibnetdiscover information\n";
+ print " -C <ca_name> use selected Channel Adaptor name for queries\n";
+ print " -P <ca_port> 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 = <IBNET_TOPO>) {
+
+ 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 0000000..baba105
--- /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] [<topology-file> | -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 0000000..0d017ba
--- /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 = <IBNET_TOPO>) {
+
+ 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 0000000..b6b27ce
--- /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 <weiny2@llnl.gov>.
+#
+# This software is available to you under a choice of one of two
+# licenses. You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, available from the file
+# COPYING in the main directory of this source tree, or the
+# OpenIB.org BSD license below:
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# - Redistributions of source code must retain the above
+# copyright notice, this list of conditions and the following
+# disclaimer.
+#
+# - Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials
+# provided with the distribution.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION 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 <guid> -D <direct route> -C <ca_name> -P <ca_port>]\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 <direct route> output only the switch specified by direct route path\n";
+ print " -S <guid> output only the switch specified by <guid> (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 <ca_name> use selected Channel Adaptor name for queries\n";
+ print " -P <ca_port> 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 0000000..5871da8
--- /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 0000000..3cac9b4
--- /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 <weiny2@llnl.gov>.
+#
+# This software is available to you under a choice of one of two
+# licenses. You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, available from the file
+# COPYING in the main directory of this source tree, or the
+# OpenIB.org BSD license below:
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# - Redistributions of source code must retain the above
+# copyright notice, this list of conditions and the following
+# disclaimer.
+#
+# - Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials
+# provided with the distribution.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION 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 <ca_guid> | <node_name>]\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 <ca_name> use selected channel adaptor name for queries\n";
+ print " -P <ca_port> 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 = <IBNET_TOPO>) {
+ 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 0000000..48c20f8
--- /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 <weiny2@llnl.gov>.
+#
+# This software is available to you under a choice of one of two
+# licenses. You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, available from the file
+# COPYING in the main directory of this source tree, or the
+# OpenIB.org BSD license below:
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# - Redistributions of source code must retain the above
+# copyright notice, this list of conditions and the following
+# disclaimer.
+#
+# - Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials
+# provided with the distribution.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION 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 <rt_guid> | <node_name>]\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 <ca_name> use selected channel adaptor name for queries\n";
+ print " -P <ca_port> 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 = <IBNET_TOPO>) {
+ 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 0000000..f20bd4b
--- /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 <weiny2@llnl.gov>.
+#
+# This software is available to you under a choice of one of two
+# licenses. You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, available from the file
+# COPYING in the main directory of this source tree, or the
+# OpenIB.org BSD license below:
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# - Redistributions of source code must retain the above
+# copyright notice, this list of conditions and the following
+# disclaimer.
+#
+# - Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials
+# provided with the distribution.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION 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 <switch_guid> | <switch_name>]\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 <ca_name> use selected channel adaptor name for queries\n";
+ print " -P <ca_port> 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 = <IBNET_TOPO>) {
+ 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 0000000..99adac7
--- /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 <weiny2@llnl.gov>.
+#
+# This software is available to you under a choice of one of two
+# licenses. You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, available from the file
+# COPYING in the main directory of this source tree, or the
+# OpenIB.org BSD license below:
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# - Redistributions of source code must retain the above
+# copyright notice, this list of conditions and the following
+# disclaimer.
+#
+# - Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials
+# provided with the distribution.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION 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 <err1,err2,...> -S <switch_guid> -D <direct route> -d -C <ca_name> -P <ca_port>]\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 <err1,err2,...> suppress errors listed\n";
+ print
+" -D <direct route> output only the switch specified by direct route path\n";
+ print " -S <switch_guid> query only <switch_guid> (hex format)\n";
+ print " -d include the data counters in the output\n";
+ print " -C <ca_name> use selected Channel Adaptor name for queries\n";
+ print " -P <ca_port> 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 0000000..6404aca
--- /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] [<topology-file> | -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 0000000..87fbb0c
--- /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 0000000..163620a
--- /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] [<topology-file> | -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 0000000..a2880aac
--- /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 <weiny2@llnl.gov>.
+#
+# This software is available to you under a choice of one of two
+# licenses. You may choose to be licensed under the terms of the GNU
+# General Public License (GPL) Version 2, available from the file
+# COPYING in the main directory of this source tree, or the
+# OpenIB.org BSD license below:
+#
+# Redistribution and use in source and binary forms, with or
+# without modification, are permitted provided that the following
+# conditions are met:
+#
+# - Redistributions of source code must retain the above
+# copyright notice, this list of conditions and the following
+# disclaimer.
+#
+# - Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following
+# disclaimer in the documentation and/or other materials
+# provided with the distribution.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION 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 <pause_time> -b -v -n <cycles> -G] <guid|lid> <port>\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 <pause_time> define the ammount of time between counter polls (default $IBswcountlimits::pause_time)\n";
+ print " -v Be verbose\n";
+ print " -n <cycles> 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 = <PERF_QUERY>) {
+ 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 0000000..855ced7
--- /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] [<name>]"
+ 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 " [<name>] 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 0000000..f1a996f
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <infiniband/common.h>
+#include <infiniband/mad.h>
+
+#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 0000000..0e2f9ac
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <arpa/inet.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+
+#include <sys/socket.h>
+
+#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)] [<lid|dr_path|guid>]\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 0000000..90e2cec
--- /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 <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <ctype.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#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 0000000..2cfaa8a
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+#include <getopt.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+#include <infiniband/complib/cl_nodenamemap.h>
+
+#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) [<topology-file>]\n",
+ argv0);
+ fprintf(stderr, " --node-name-map <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 0000000..4fd2dcb
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+#include <signal.h>
+#include <getopt.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+
+#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)] <dest lid|guid>\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 0000000..36453bb
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+
+#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] <dest dr_path|lid|guid> <portnum> [<op>]\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 0000000..f2ee170
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+#include <inttypes.h>
+#include <getopt.h>
+#include <netinet/in.h>
+#include <ctype.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+#include <infiniband/complib/cl_nodenamemap.h>
+
+#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] [<dest dr_path|lid|guid> [<startlid> [<endlid>]]]\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 0000000..66620de
--- /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 <weiny2@llnl.gov>.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#include <infiniband/mad.h>
+#include <infiniband/iba/ib_types.h>
+
+#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(&notice, 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, &notice));
+}
+
+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 <ca_name>] [-P <ca_port>] [<trap_name>]\n", argv0);
+ fprintf(stderr, " -V print version\n");
+ fprintf(stderr, " <trap_name> 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 0000000..600a657
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <string.h>
+#include <getopt.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <sys/poll.h>
+#include <syslog.h>
+#include <netinet/in.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+
+#include <ibdiag_common.h>
+
+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)] <ca_name> [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 0000000..e3d0b9f
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+#include <getopt.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+
+#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)] <dest lid|guid> [<op>]\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 0000000..bde0ea7
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <netinet/in.h>
+#include <inttypes.h>
+#include <errno.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+#include <infiniband/complib/cl_nodenamemap.h>
+
+#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 ] <src-addr> <dest-addr>\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 0000000..9285b95
--- /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 <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+
+#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 0000000..7a53e92
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <netinet/in.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+
+#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)] [<lid|guid> [[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 0000000..97663d1
--- /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 <weiny2@llnl.gov>.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+
+#define _GNU_SOURCE
+#include <getopt.h>
+
+#include <infiniband/mad.h>
+#include <infiniband/opensm/osm_log.h>
+#include <infiniband/vendor/osm_vendor_api.h>
+#include <infiniband/vendor/osm_vendor_sa_api.h>
+#include <infiniband/opensm/osm_mad_pool.h>
+#include <infiniband/complib/cl_debug.h>
+#include <infiniband/complib/cl_nodenamemap.h>
+
+#include <netinet/in.h>
+
+#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 = "<unknown>";
+
+ /* 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 <src:dst> --sgid-to-dgid <src-dst> "
+ "-C <ca_name> -P <ca_port> -t(imeout) <msec>] [query-name] [<name> | <lid> | <guid>]\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 <src:dst>\n"
+ " where src and dst are either node "
+ "names or LIDs\n");
+ fprintf(stderr, " --sgid-to-dgid get a PathRecord for <sgid-dgid>\n"
+ " where sgid and dgid are addresses in "
+ "IPv6 format\n");
+ fprintf(stderr, " -C <ca_name> specify the SA query HCA\n");
+ fprintf(stderr, " -P <ca_port> specify the SA query port\n");
+ fprintf(stderr, " --smkey <val> 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 <msec> specify the SA query "
+ "response timeout (default %u msec)\n", DEFAULT_SA_TIMEOUT_MS);
+ fprintf(stderr,
+ " --node-name-map <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 <node>:<node>\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 <GID>-<GID>\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 0000000..c811057
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <inttypes.h>
+#include <getopt.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+
+#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] <sm_lid|sm_dr_path> [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 0000000..de2ee8d
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <sys/poll.h>
+#include <syslog.h>
+#include <netinet/in.h>
+
+#include <infiniband/common.h>
+#include <infiniband/mad.h>
+#include <infiniband/umad.h>
+
+#include <ibdiag_common.h>
+
+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] <dlid|dr_path> <attr> [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 0000000..ed8ec83
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <time.h>
+#include <string.h>
+#include <getopt.h>
+#include <netinet/in.h>
+
+#define __STDC_FORMAT_MACROS
+#include <inttypes.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+#include <infiniband/complib/cl_nodenamemap.h>
+
+#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> <dest dr_path|lid|guid> [op params]\n",
+ basename);
+ fprintf(stderr, "\tsupported ops:\n");
+ for (r = match_tbl ; r->name ; r++) {
+ fprintf(stderr, "\t\t%s <addr>%s\n", r->name,
+ r->opt_portnum ? " [<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 0000000..0674986
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <getopt.h>
+#include <netinet/in.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <infiniband/mad.h>
+
+#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)] <lid|guid>\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 0000000..d09c13f
--- /dev/null
+++ b/contrib/ofed/management/libibcommon/AUTHORS
@@ -0,0 +1,3 @@
+Shahar Frank <shahar@voltaire.com>
+Hal Rosenstock <halr@voltaire.com>
+Sasha Khapyorsky <sashak@voltaire.com>
diff --git a/contrib/ofed/management/libibcommon/COPYING b/contrib/ofed/management/libibcommon/COPYING
new file mode 100644
index 0000000..1b1ca1d
--- /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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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 0000000..0fdeaa9
--- /dev/null
+++ b/contrib/ofed/management/libibcommon/ChangeLog
@@ -0,0 +1,21 @@
+2007-06-29 Hal Rosenstock <halr@voltaire.com>
+
+ * Release version 1.0.4
+
+2007-06-26 Hal Rosenstock <halr@voltaire.com>
+
+ * src/sysfs.c: Change uint to unsigned for strict ANSI
+
+2007-06-26 Michael S. Tsirkin <mst@dev.mellanox.co.il>
+
+ * include/infiniband/common.h: Change uint to unsigned
+ for strict ANSI
+
+2007-01-25 Hal Rosenstock <halr@voltaire.com>
+
+ * Release version 1.0.2.
+
+2006-11-20 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * 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 0000000..75889f4
--- /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 0000000..4827884
--- /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 0000000..0f2fc33
--- /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 0000000..e955593
--- /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 <stdio.h>
+#include <sys/select.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdint.h>
+#include <infiniband/byteswap.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 __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 0000000..bd328b0
--- /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 0000000..7b88f1b
--- /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 0000000..05fbff2
--- /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 <common.h>
+
+#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<n; ++i) h = hash( k[i], len[i], h);
+
+--------------------------------------------------------------------
+*/
+
+uint32_t
+fhash(uint8_t *k, int length, uint32_t initval)
+{
+ uint32_t a, b, c, len;
+
+ /* Set up the internal state */
+ len = length;
+ a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
+ c = initval; /* the previous hash value */
+
+ /* handle most of the key */
+ while (len >= 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 0000000..5829158
--- /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 0000000..a51edae
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <string.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <sys/poll.h>
+#include <syslog.h>
+#include <time.h>
+#include <signal.h>
+
+#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 0000000..dfa722f
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <string.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <sys/poll.h>
+#include <syslog.h>
+#include <netinet/in.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#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 0000000..7354d6a
--- /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 <common.h>
+#include <sys/time.h>
+
+/**
+ * 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 0000000..4b91644
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <inttypes.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <string.h>
+#include <endian.h>
+#include <byteswap.h>
+#include <sys/poll.h>
+#include <syslog.h>
+#include <netinet/in.h>
+
+#include <common.h>
+
+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 0000000..d09c13f
--- /dev/null
+++ b/contrib/ofed/management/libibmad/AUTHORS
@@ -0,0 +1,3 @@
+Shahar Frank <shahar@voltaire.com>
+Hal Rosenstock <halr@voltaire.com>
+Sasha Khapyorsky <sashak@voltaire.com>
diff --git a/contrib/ofed/management/libibmad/COPYING b/contrib/ofed/management/libibmad/COPYING
new file mode 100644
index 0000000..1b1ca1d
--- /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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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 0000000..0c4c337
--- /dev/null
+++ b/contrib/ofed/management/libibmad/ChangeLog
@@ -0,0 +1,88 @@
+2008-06-15 Max Matveev <makc@sgi.com>
+ * 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 <halr@voltaire.com>
+
+ * Release version 1.1.1.
+
+2007-06-26 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <mst@dev.mellanox.co.il>
+
+ * include/infiniband/mad.h: Change uint to unsigned
+ for strict ANSI
+
+2007-06-18 Hal Rosenstock <halr@voltaire.com>
+
+ * include/infiniband/mad.h, src/fields.c: Change IB_PORT_MTRU_CAP_F
+ to IB_PORT_MTU_CAP_F
+
+2007-06-05 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * include/infiniband/mad.h, src/fields.c: Add Notice DataDetails
+ fields for DataDetails, and trap 144 LID and CapabilityMask
+
+2007-05-21 Hal Rosenstock <halr@voltaire.com>
+
+ * src/fields.c: Changed PortMulticastPkts to PortMulticastRcvPkts
+
+2007-03-29 Hal Rosenstock <halr@voltaire.com>
+
+ * src/fields.c: Changed Xmt/RcvBytes to Xmt/RcvData
+
+2007-03-29 Hal Rosenstock <halr@voltaire.com>
+
+ * Release version 1.1.0.
+
+2007-03-22 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * include/infiniband/mad.h, src/fields.c: Add encode/decode
+ support for GUID0 in SM GUIDInfo attribute
+
+2007-03-14 Dotan Barak <dotanb@mellanox.co.il>
+
+ * include/infiniband/mad.h: Add GUIDInfo as SM attribute ID
+
+2007-02-08 Ira Weiny <weiny2@llnl.gov>
+
+ * src/portid.c: Change DR path output to be comma separated
+ decimal values like OpenSM
+
+2007-01-25 Hal Rosenstock <halr@voltaire.com>
+
+ * Release version 1.0.2.
+
+2006-12-11 Hal Rosenstock <halr@voltaire.com>
+
+ * src/(sa serv smp vendor).c: Change some debug parameters
+ to hex from decimal
+
+2006-11-20 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * src/rpc.c: Fix various uses of printf() style functions
+
+2006-10-20 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * 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 0000000..beae1a4
--- /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 0000000..4827884
--- /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 0000000..3d8e73d
--- /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([<infiniband/common.h> not found. libibmad requires libibcommon.])
+)
+AC_CHECK_HEADER(infiniband/umad.h, [],
+ AC_MSG_ERROR([<infiniband/umad.h> 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 0000000..c2ad148
--- /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 <stdint.h>
+#include <string.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 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 0000000..5fd10f6
--- /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 0000000..51f2b71
--- /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 0000000..052127f
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <inttypes.h>
+#include <netinet/in.h>
+
+#include <mad.h>
+#include <infiniband/common.h>
+
+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 0000000..6942e85
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <mad.h>
+#include <infiniband/common.h>
+
+/*
+ * 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 0000000..89c927e
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/time.h>
+
+#include <infiniband/umad.h>
+#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 0000000..f26d28d
--- /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 0000000..1367ecd
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/time.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <mad.h>
+
+#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 0000000..24a555b
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <string.h>
+#include <inttypes.h>
+#include <arpa/inet.h>
+
+#include <mad.h>
+#include <infiniband/common.h>
+
+#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 0000000..a33acd8
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <string.h>
+#include <errno.h>
+
+#include <infiniband/umad.h>
+#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 0000000..25062f6
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <mad.h>
+
+#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 0000000..f27c5af
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <string.h>
+#include <errno.h>
+
+#include <infiniband/umad.h>
+#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 0000000..2e092ec
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <mad.h>
+#include <infiniband/common.h>
+
+#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 0000000..9b20cb6
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <sys/time.h>
+#include <string.h>
+#include <netinet/in.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.h>
+#include <mad.h>
+
+#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 0000000..2c2bde2
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/time.h>
+
+#include <mad.h>
+#include <infiniband/common.h>
+
+#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 0000000..468e2d3
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/time.h>
+
+#include <mad.h>
+#include <infiniband/common.h>
+
+#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 0000000..d09c13f
--- /dev/null
+++ b/contrib/ofed/management/libibumad/AUTHORS
@@ -0,0 +1,3 @@
+Shahar Frank <shahar@voltaire.com>
+Hal Rosenstock <halr@voltaire.com>
+Sasha Khapyorsky <sashak@voltaire.com>
diff --git a/contrib/ofed/management/libibumad/COPYING b/contrib/ofed/management/libibumad/COPYING
new file mode 100644
index 0000000..1b1ca1d
--- /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.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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.
+
+ <signature of Ty Coon>, 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 0000000..f394ef8
--- /dev/null
+++ b/contrib/ofed/management/libibumad/ChangeLog
@@ -0,0 +1,94 @@
+2007-07-10 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <sean.hefty@intel.com>
+
+ * include/infiniband/umad.h: Clarify that umad_set_pkey()
+ takes a pkey index, and not the pkey itself
+
+2007-06-26 Hal Rosenstock <halr@voltaire.com>
+
+ * src/umad.c: Change uint to unsigned for strict ANSI
+
+2007-06-26 Michael S. Tsirkin <mst@dev.mellanox.co.il>
+
+ * include/infiniband/umad.h: Change uint to unsigned
+ for strict ANSI
+
+2007-05-24 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <weiny2@llnl.gov>
+
+ * libibumad.spec.in: Add man pages
+
+2007-05-21 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * Release version 1.1.1.
+
+ * Makefile.am: Added man pages support
+
+ * man: Add initial version of libibumad man pages
+
+2007-04-24 Roland Dreier <rolandd@cisco.com>
+
+ * src/umad.c: In umad_open_port, fix declaration of
+ return value from dev_to_umad_id
+
+2007-04-24 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * Release version 1.1.0.
+
+2007-03-22 Hal Rosenstock <halr@voltaire.com>
+
+ * src/umad.c: Implement GRH support in umad_set_grh
+
+2007-03-11 Dotan Barak <dotanb@mellanox.co.il>
+
+ * src/umad.c: In umad_get_ca_portguids, add release_ca call
+ in error flow to prevent resource leak
+
+2007-01-25 Hal Rosenstock <halr@voltaire.com>
+
+ * Release version 1.0.2.
+
+2006-11-20 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * src/umad.c: Fix various uses of printf() style functions
+
+2006-10-31 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * src/umad.c (umad_set_addr_net): Fix endian used in
+ TRACE macro
+
+2006-09-28 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * 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 0000000..1e3e6fd
--- /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 0000000..4827884
--- /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 0000000..ad3afcd
--- /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([<infiniband/common.h> 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 <valgrind/memcheck.h> header file.])],
+ [if test $want_valgrind = yes; then
+ AC_MSG_ERROR([Valgrind memcheck support requested, but <valgrind/memcheck.h> 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 0000000..cc5bef5
--- /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 <stdint.h>
+#include <infiniband/common.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 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 <stdlib.h>
+
+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 0000000..1b11d18
--- /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 0000000..21cf1ed
--- /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 0000000..7f09214
--- /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 <infiniband/umad.h>
+.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 <infiniband/umad.h>.
+.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 <halr@voltaire.com>
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 0000000..5c65f3e
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..2c56d90
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..b7da2b0
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
+.TP
+Dotan Barak <dotanb@mellanox.co.il>
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 0000000..101a2e0
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..ac39794
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..2f5fd1a
--- /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 <infiniband/umad.h>
+.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 <infiniband/umad.h>.
+.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 <halr@voltaire.com>
+.TP
+Dotan Barak <dotanb@mellanox.co.il>
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 0000000..3512649
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
+.TP
+Dotan Barak <dotanb@mellanox.co.il>
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 0000000..85e76f8
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
+.TP
+Dotan Barak <dotanb@mellanox.co.il>
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 0000000..49aa839
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..ac538c9
--- /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 <infiniband/umad.h>
+.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 <sashak@voltaire.com>
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 0000000..78c59ac
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..5da86c2
--- /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 <infiniband/umad.h>
+.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 <infiniband/umad.h>.
+.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 <halr@voltaire.com>
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 0000000..a03c0a6
--- /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 <infiniband/umad.h>
+.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 <sashak@voltaire.com>
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 0000000..863afa7
--- /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 <infiniband/umad.h>
+.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 <infiniband/umad.h>.
+.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 <halr@voltaire.com>
+.TP
+Dotan Barak <dotanb@mellanox.co.il>
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 0000000..a810877
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
+.TP
+Dotan Barak <dotanb@mellanox.co.il>
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 0000000..53f2946
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..93f9425
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..e1b2985
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..7f11b51
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..4e8171c
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..2d84f57
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..82f8190
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..1f409c2
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..17fe73b
--- /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 <infiniband/umad.h>
+.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 <infiniband/umad.h>.
+The argument
+.I umad
+is a pointer to an
+.I ib_user_mad_t
+struct, as specified in
+.I <infiniband/umad.h>.
+.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 <halr@voltaire.com>
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 0000000..8425b3f
--- /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 <infiniband/umad.h>
+.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 <infiniband/umad.h>.
+The argument
+.I umad
+is a pointer to an
+.I ib_user_mad_t
+struct, as specified in
+.I <infiniband/umad.h>.
+.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 <halr@voltaire.com>
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 0000000..d6b8606
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..db861ef
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..3978b84
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
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 0000000..472afec
--- /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 <infiniband/umad.h>
+.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 <halr@voltaire.com>
diff --git a/contrib/ofed/management/libibumad/src/libibumad.map b/contrib/ofed/management/libibumad/src/libibumad.map
new file mode 100644
index 0000000..0154b7f
--- /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 0000000..00fcff6
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/poll.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <ctype.h>
+
+#include "umad.h"
+
+#define IB_OPENIB_OUI (0x001405)
+
+#ifdef HAVE_VALGRIND_MEMCHECK_H
+
+# include <valgrind/memcheck.h>
+
+# 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 0000000..b5b587c
--- /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 | <key-id> ]"
+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 <component>-git.tar.gz and will overwrite existing tarballs."
+echo "If this is a release build, then the tarball will be named"
+echo "<component>-<version>.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 <component>-<version> 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 <target>.spec.in"
+echo "file and output a <target>.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 0000000..0106a07
--- /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 0000000..07e5ab0
--- /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 0000000..cb67d2b
--- /dev/null
+++ b/contrib/ofed/management/opensm/ChangeLog
@@ -0,0 +1,14 @@
+2005-09-12 Hal Rosenstock <halr@voltaire.com>
+
+ * Improved SA MCMemberRecord error messages
+
+2005-08-22 Yael Kalka <yael@mellanox.co.il>
+
+ * Merge of OpenSM 1.8.0 previously available only on Gen1
+
+2005-08-14 Eitan Zahavi <eitan@mellanox.co.il>
+
+ * 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 0000000..095b1eb
--- /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 0000000..2287edd
--- /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 0000000..8887552
--- /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 0000000..40556ba
--- /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 0000000..fee8800
--- /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 0000000..2b13147
--- /dev/null
+++ b/contrib/ofed/management/opensm/complib/ChangeLog
@@ -0,0 +1,96 @@
+2007-07=11 Hal Rosenstock <halr@voltaire.com>
+
+ * configure.in: to version 2.2.1
+
+2007-06-25 Hal Rosenstock <halr@voltaire.com>
+
+ * cl_event_wheel.c: Fix some typos in printfs when
+ __CL_EVENT_WHEEL_TEST__ defined
+
+2007-06-20 Hal Rosenstock <halr@voltaire.com>
+
+ * libosmcomp.map: Add get_next map functions as global
+
+2007-06-20 Todd Rimmer <todd.rimmer@qlogic.com>
+
+ * 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 <todd.rimmer@qlogic.com>
+
+ * include/complib/cl_qmap.h: In cl_qmap_remove_all, make
+ sure the count field is properly maintained.
+
+2007-06-19 Hal Rosenstock <halr@voltaire.com>
+
+ * include/complib/cl_threadpool.h: Eliminate compile warning
+ with cl_threadpool.c introduced by previous change
+
+2007-06-13 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * include/complib/cl_threadpool.h, complib/cl_threadpool.c,
+ complib/cl_dispatcher.c, complib/libosmcomp.map: Thread
+ pool rework
+
+2007-06-13 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <kliteyn@dev.mellanox.co.il>
+
+ * 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 <halr@voltaire.com>
+
+ * configure.in: Bump to version 2.1.2
+
+2007-03-29 Hal Rosenstock <halr@voltaire.com>
+
+ * configure.in: Bump to version 2.1.1
+
+2007-01-08 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * cl_log.c: SIGUSR1 fixes
+
+2007-01-08 Ira Weiny <weiny2@llnl.gov>
+
+ * cl_log.c: Add SIGUSR1 handling to reopen osm.log
+
+2006-10-31 Hal Rosenstock <halr@voltaire.com>
+
+ * configure.in: Bumped to version version 2.1.0
+
+2006-09-05 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * cl_event_wheel.c: Changes to support new osm_log
+ initializer osm_log_init_v2()
+
+2006-08-29 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * cl_event_wheel.c: Support option to limit size of OpenSM
+ log file
+
+2006-07-20 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * cl_pool.c: Fix memory corruption in cl_qcpool_init
+
+2006-07-19 Hal Rosenstock <halr@voltaire.com>
+
+ * Makefile.am: Eliminate deprecated warnings
+
+2006-06-11 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 0000000..6f2f203
--- /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 0000000..2449d9d
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <complib/cl_types.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_spinlock.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+/*
+ * 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 0000000..b0a0a76
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <complib/cl_dispatcher.h>
+#include <complib/cl_thread.h>
+#include <complib/cl_timer.h>
+
+/* 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 0000000..d14b2f4
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <complib/cl_event.h>
+#include <complib/cl_debug.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+
+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 0000000..ca06882
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <math.h>
+#include <stdlib.h>
+#include <complib/cl_event_wheel.h>
+#include <complib/cl_debug.h>
+
+#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 0000000..8129c61
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <complib/cl_qlist.h>
+#include <complib/cl_list.h>
+
+#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 0000000..a2a1372
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <complib/cl_log.h>
+#include <complib/cl_debug.h>
+#include <syslog.h>
+
+/* 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 0000000..c0e44be
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_map.h>
+#include <complib/cl_fleximap.h>
+
+/******************************************************************************
+*******************************************************************************
+************** ************
+************** 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 0000000..4c6e8a4
--- /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 <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <ctype.h>
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <complib/cl_nodenamemap.h>
+
+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 0000000..0790304
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <complib/cl_qcomppool.h>
+#include <complib/cl_comppool.h>
+#include <complib/cl_qpool.h>
+#include <complib/cl_pool.h>
+#include <complib/cl_math.h>
+
+/*
+ * 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 0000000..c34316e
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <complib/cl_ptr_vector.h>
+
+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 0000000..2d81696c
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <complib/cl_spinlock.h>
+
+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 0000000..b02b8b8
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <complib/cl_types.h>
+
+/* 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 0000000..38a68f8
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <complib/cl_thread.h>
+
+/*
+ * 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 0000000..3f6c0a4
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include <complib/cl_threadpool.h>
+
+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 0000000..41b669f
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <complib/cl_timer.h>
+#include <sys/time.h>
+#include <sys/errno.h>
+#include <stdio.h>
+
+/* 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 0000000..d9bcf34
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <complib/cl_vector.h>
+
+/*
+ * 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 0000000..52b2adc
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <complib/cl_types.h>
+
+/* 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 0000000..788eb2a
--- /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 0000000..f076585
--- /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 0000000..c7798cc
--- /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=<type>],
+ [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=<dir>],
+ [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=<dir>],
+ [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=<dir>],
+ [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=<dir>],
+ [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 0000000..4479031
--- /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 <sysconfdir> 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 <sysconfdir>/<dir> (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 0000000..31d4c83
--- /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 0000000..700924f
--- /dev/null
+++ b/contrib/ofed/management/opensm/doc/OpenSM_RN.pdf
Binary files 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 0000000..ae32826
--- /dev/null
+++ b/contrib/ofed/management/opensm/doc/OpenSM_UM.pdf
Binary files 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 0000000..8c9915f
--- /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 : <SL>
+ ipoib, pkey 0x7fff : <SL>
+ any, pkey 0x7fff : <SL>
+
+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 : <SL>
+ any, service-id 0x0000000000010000-0x000000000001ffff : <SL>
+
+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 : <SL>
+ any, service-id 0x00000000010648CA : <SL>
+
+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 : <SL>
+ any, service-id 0x0000000001060CBC : <SL>
+
+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 : <SL>
+ any, target-port-guid 0x1234 : <SL>
+
+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_<type>_" 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_<type>_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 0000000..af008bc
--- /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 <equalize-ignore-guids-file>
+-ignore-guids <equalize-ignore-guids-file>
+ 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 <guid_list_file>' 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 0000000..3f2174b
--- /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 0000000..379042c
--- /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 0000000..2b6253d
--- /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 0000000..5d8366c
--- /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 0000000..3356e95
--- /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 <file-name>' 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 0000000..ea1f6a9
--- /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 0000000..02caaf8
--- /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 0000000..51bd21c
--- /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 <your routing file>" or
+ "--routing_engine file --ucast_file <your routing 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 <size in MB>" or
+ "--log_limit <size in MB>" 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 0000000..b48f148
--- /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 0000000..602cc66
--- /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>:<PortGUIDs list> ;
+
+
+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=<val> - specifies rate for this IPoIB MC group (default is 3 (10GBps))
+mtu=<val> - specifies MTU for this IPoIB MC group (default is 4 (2048))
+sl=<val> - specifies SL for this IPoIB MC group (default is 0)
+scope=<val> - 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 0000000..f908ccf
--- /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 0000000..0b35e5f
--- /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:
+
+<snip>
+"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
+</snip>
+
+
+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 0000000..ac7312f
--- /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_<type>_"
+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 0000000..bbb9698
--- /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 0000000..1df1abc
--- /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 0000000..92620ee
--- /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 <complib/cl_atomic_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
+/****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 0000000..ac14f8a
--- /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 <complib/cl_types.h>
+#include <complib/cl_spinlock.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 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 0000000..ca144e3
--- /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 <string.h>
+#include <complib/cl_byteswap_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
+/****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 0000000..72ff40e
--- /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 <endian.h>
+#include <byteswap.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 __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 0000000..503ae18
--- /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 <complib/cl_qcomppool.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* 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 0000000..05e9769
--- /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 <complib/cl_debug_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
+/****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 0000000..b61891b
--- /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 <complib/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
+#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 <inttypes.h>
+#include <stdio.h>
+#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 0000000..a5b4a28
--- /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 <complib/cl_atomic.h>
+#include <complib/cl_threadpool.h>
+#include <complib/cl_qlist.h>
+#include <complib/cl_qpool.h>
+#include <complib/cl_spinlock.h>
+#include <complib/cl_ptr_vector.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* 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 0000000..10805fb
--- /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 <complib/cl_event_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
+/****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 0000000..541ced0
--- /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 <complib/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 <pthread.h> /* 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 0000000..ac02242
--- /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 <complib/cl_atomic.h>
+#include <complib/cl_qlist.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_timer.h>
+#include <complib/cl_spinlock.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* 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 0000000..0af8766
--- /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 <complib/cl_qmap.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* 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 0000000..5d40b19
--- /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 <complib/cl_qlist.h>
+#include <complib/cl_qpool.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* 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 0000000..45c7ec3
--- /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 <complib/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
+/****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 0000000..5bf779c
--- /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 <complib/cl_qmap.h>
+#include <complib/cl_qpool.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* 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 0000000..47489bd
--- /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 <complib/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
+/****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 0000000..9b2ada4
--- /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 <stdio.h>
+#include <stdint.h>
+#include <complib/cl_qmap.h>
+
+/* 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 0000000..52ee381
--- /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 0000000..ffc8e11
--- /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 <complib/ipackon.h>
+*
+* typedef _my_struct_t
+* {
+* uint64 large;
+* uint32 medium;
+* uint16 small;
+*
+* } PACK_SUFFIX my_struct_t;
+* #include <complib/ipackoff.h>
+*********/
+
+#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 0000000..bafd339
--- /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 <complib/cl_types.h>
+#include <pthread.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* 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 0000000..f01de96
--- /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 <complib/cl_qcomppool.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* 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 0000000..d4af0fe
--- /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 <complib/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
+/****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 0000000..58862e3
--- /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 <complib/cl_types.h>
+#include <complib/cl_qlist.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* 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 0000000..accbd98
--- /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 <complib/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
+/****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 0000000..130c2ef
--- /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 <complib/cl_qpool.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* 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 0000000..f144cb3
--- /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 <complib/cl_qcomppool.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* 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 0000000..1a04b56
--- /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 <complib/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
+/****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 0000000..beb6405
--- /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 <complib/cl_types.h>
+#include <pthread.h> /* 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 0000000..0a622a1
--- /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 <complib/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
+/****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 0000000..ad7df90
--- /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 <complib/cl_types.h>
+#include <complib/cl_event.h>
+#include <pthread.h>
+/* 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 0000000..e9b2c78
--- /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 <pthread.h>
+#include <complib/cl_types.h>
+#include <complib/cl_thread.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* 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 0000000..194e374
--- /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 <complib/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
+/****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 <complib/cl_timer_osd.h>
+
+/****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 0000000..ed36fea
--- /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 <complib/cl_types.h>
+#include <complib/cl_spinlock.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 <complib/cl_qlist.h>
+#include <pthread.h>
+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 0000000..848b9d9
--- /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 <complib/cl_types_osd.h>
+#include <stddef.h>
+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 <cl_statustext.c>. %%
+%% %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%*/
+
+/****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 0000000..d12aa4c
--- /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 <inttypes.h>
+#include <assert.h>
+#include <string.h>
+#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 0000000..11c45f8
--- /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 <complib/cl_qlist.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* 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 0000000..c1fbfaf
--- /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 <iba/ib_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
+/*
+ * 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 0000000..0f9d110
--- /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 <string.h>
+#include <complib/cl_types.h>
+#include <complib/cl_byteswap.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( 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/************/
+
+/****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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/**********/
+#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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+#include <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+/****s* IBA Base: Types/ib_port_info_t
+* NAME
+* ib_port_info_t
+*
+* DESCRIPTION
+* IBA defined PortInfo. (14.2.5.6)
+*
+* SYNOPSIS
+*/
+#include <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/************/
+
+#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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+#include <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+#include <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+#include <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+/****s* IBA Base: Types/ib_lft_record_t
+* NAME
+* ib_lft_record_t
+*
+* DESCRIPTION
+* IBA defined LinearForwardingTableRecord (15.2.5.6)
+*
+* SYNOPSIS
+*/
+#include <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/************/
+
+/****s* IBA Base: Types/ib_mft_record_t
+* NAME
+* ib_mft_record_t
+*
+* DESCRIPTION
+* IBA defined MulticastForwardingTableRecord (15.2.5.8)
+*
+* SYNOPSIS
+*/
+#include <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/************/
+
+/****s* IBA Base: Types/ib_switch_info_t
+* NAME
+* ib_switch_info_t
+*
+* DESCRIPTION
+* IBA defined SwitchInfo. (14.2.5.4)
+*
+* SYNOPSIS
+*/
+#include <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/************/
+
+#include <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+#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 <complib/cl_packon.h>
+typedef struct _ib_guid_info {
+ ib_net64_t guid[GUID_TABLE_MAX_ENTRIES];
+
+} PACK_SUFFIX ib_guid_info_t;
+#include <complib/cl_packoff.h>
+/************/
+
+#include <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+#define IB_MULTIPATH_MAX_GIDS 11 /* Support max that can fit into first MAD (for now) */
+
+#include <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+typedef struct _ib_pkey_table {
+ ib_net16_t pkey_entry[IB_NUM_PKEY_ELEMENTS_IN_BLOCK];
+
+} PACK_SUFFIX ib_pkey_table_t;
+#include <complib/cl_packoff.h>
+/************/
+
+/****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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/************/
+
+#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 <complib/cl_packon.h>
+typedef struct _ib_slvl_table {
+ uint8_t raw_vl_by_sl[IB_MAX_NUM_VLS / 2];
+} PACK_SUFFIX ib_slvl_table_t;
+#include <complib/cl_packoff.h>
+/************/
+
+/****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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/************/
+
+/****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 <complib/cl_packon.h>
+typedef struct _ib_vl_arb_element {
+ uint8_t vl;
+ uint8_t weight;
+} PACK_SUFFIX ib_vl_arb_element_t;
+#include <complib/cl_packoff.h>
+/************/
+
+#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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/************/
+
+/****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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/************/
+
+/*
+ * Global route header information received with unreliable datagram messages
+ */
+#include <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+/****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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+/**
+ * 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+/****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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+/****s* IBA Base: Types/ib_perfmgt_mad_t
+* NAME
+* ib_perfmgt_mad_t
+*
+* DESCRIPTION
+* IBA defined Perf Management MAD (16.3.1)
+*
+* SYNOPSIS
+*/
+#include <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+#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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+/****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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+/****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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+/****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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+/*
+* 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 <complib/cl_packon.h>
+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 <complib/cl_packoff.h>
+
+/*
+ * 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 <iba/ib_types_extended.h>
+#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 0000000..e79073b
--- /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 <opensm/osm_path.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
+/*
+ * 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 0000000..54df41e
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#ifdef __WIN__
+#include <vendor/winosm_common.h>
+#define OSM_CDECL __cdecl
+#else
+#define OSM_CDECL
+#endif
+
+#include <complib/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
+/****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 "<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 <ref to 15.4.4>. 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 0000000..8ecaa79
--- /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 0000000..b12006f
--- /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 0000000..3ea8fa5
--- /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 <opensm/osm_opensm.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
+// 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 0000000..5fe233d
--- /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 <opensm/osm_subnet.h>
+#include <opensm/osm_log.h>
+
+#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 0000000..56bae31
--- /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 <complib/cl_list.h>
+#include <complib/cl_spinlock.h>
+#include <opensm/osm_log.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/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 0000000..83861a6
--- /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 <opensm/osm_db.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
+/****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 0000000..aff4300
--- /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 0000000..0922c65
--- /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 <time.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qlist.h>
+#include <opensm/osm_config.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 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 0000000..9222853
--- /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 <iba/ib_types.h>
+#include <complib/cl_dispatcher.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_path.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
+/*
+ * 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 0000000..1528642
--- /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 <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_spinlock.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_sa.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/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 0000000..714ba41
--- /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 <complib/cl_passivelock.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_db.h>
+#include <opensm/osm_log.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 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 0000000..20999d9
--- /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 <syslog.h>
+#endif
+#include <complib/cl_spinlock.h>
+#include <opensm/osm_base.h>
+#include <iba/ib_types.h>
+#include <stdio.h>
+
+#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 0000000..0aa5b46
--- /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 <iba/ib_types.h>
+#include <complib/cl_atomic.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_madw.h>
+#include <vendor/osm_vendor.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/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 0000000..f47142d
--- /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 <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qlist.h>
+#include <complib/cl_dispatcher.h>
+#include <opensm/osm_base.h>
+#include <vendor/osm_vendor.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: 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 0000000..15b95cf
--- /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 <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <opensm/osm_base.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: 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 0000000..dec607f
--- /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 <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qlist.h>
+#include <opensm/osm_base.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: 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 0000000..c2b18de
--- /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 <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <opensm/osm_base.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: 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 0000000..dbf3e53
--- /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 0000000..ef696da
--- /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 <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_switch.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 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 0000000..bd219d1
--- /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 <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_qlist.h>
+#include <complib/cl_spinlock.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_mtree.h>
+#include <opensm/osm_mcm_port.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_log.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/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 0000000..50b3598
--- /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 <complib/cl_qmap.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_path.h>
+#include <opensm/osm_madw.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
+
+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 0000000..c121be4
--- /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 <stdio.h>
+#include <complib/cl_qlist.h>
+#include <complib/cl_dispatcher.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_atomic.h>
+#include <complib/cl_nodenamemap.h>
+#include <opensm/osm_console_io.h>
+#include <opensm/osm_stats.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_sm.h>
+#include <opensm/osm_sa.h>
+#include <opensm/osm_perfmgr.h>
+#include <opensm/osm_event_plugin.h>
+#include <opensm/osm_db.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_vl15intf.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/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 0000000..38acdc9
--- /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 <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_map.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_subnet.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/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 0000000..8d65d2c
--- /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 <string.h>
+#include <opensm/osm_base.h>
+#include <vendor/osm_vendor_api.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
+/*
+ * 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 0000000..d48d2ee
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#ifdef ENABLE_OSM_PERF_MGR
+
+#include <iba/ib_types.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_event.h>
+#include <complib/cl_timer.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_perfmgr_db.h>
+#include <opensm/osm_sm.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_event_plugin.h>
+
+#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 0000000..c28d5bb
--- /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 <stdio.h>
+#include <time.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.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
+
+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 0000000..94b7207
--- /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 <iba/ib_types.h>
+#include <complib/cl_dispatcher.h>
+#include <complib/cl_map.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_log.h>
+#include <opensm/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
+/*
+ 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 0000000..91587bd
--- /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 <opensm/osm_base.h>
+#include <opensm/osm_opensm.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
+/****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 0000000..3dda541
--- /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 <complib/cl_qmap.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_path.h>
+#include <opensm/osm_pkey.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
+/*
+ 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 0000000..fd227190
--- /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 <string.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_mcast_tbl.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/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 0000000..829a9ff
--- /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 <complib/cl_types.h>
+#include <complib/cl_qlist.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 {
+ 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 0000000..c38624b
--- /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 <iba/ib_types.h>
+#include <complib/cl_list.h>
+#include <opensm/st.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_partition.h>
+
+#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)<<IB_NODE_TYPE_CA)
+#define OSM_QOS_POLICY_NODE_TYPE_SWITCH (((uint8_t)1)<<IB_NODE_TYPE_SWITCH)
+#define OSM_QOS_POLICY_NODE_TYPE_ROUTER (((uint8_t)1)<<IB_NODE_TYPE_ROUTER)
+
+/***************************************************/
+
+typedef struct osm_qos_port {
+ cl_map_item_t map_item;
+ osm_physp_t * p_physp;
+} osm_qos_port_t;
+
+typedef struct osm_qos_port_group {
+ char *name; /* single string (this port group name) */
+ char *use; /* single string (description) */
+ uint8_t node_types; /* node types bitmask */
+ cl_qmap_t port_map;
+} osm_qos_port_group_t;
+
+/***************************************************/
+
+typedef struct osm_qos_vlarb_scope {
+ cl_list_t group_list; /* list of group names (strings) */
+ cl_list_t across_list; /* list of 'across' group names (strings) */
+ cl_list_t vlarb_high_list; /* list of num pairs (n:m,...), 32-bit values */
+ cl_list_t vlarb_low_list; /* list of num pairs (n:m,...), 32-bit values */
+ uint32_t vl_high_limit; /* single integer */
+ boolean_t vl_high_limit_set;
+} osm_qos_vlarb_scope_t;
+
+/***************************************************/
+
+typedef struct osm_qos_sl2vl_scope {
+ cl_list_t group_list; /* list of strings (port group names) */
+ boolean_t from[OSM_QOS_POLICY_MAX_PORTS_ON_SWITCH];
+ boolean_t to[OSM_QOS_POLICY_MAX_PORTS_ON_SWITCH];
+ cl_list_t across_from_list; /* list of strings (port group names) */
+ cl_list_t across_to_list; /* list of strings (port group names) */
+ uint8_t sl2vl_table[16]; /* array of sl2vl values */
+ boolean_t sl2vl_table_set;
+} osm_qos_sl2vl_scope_t;
+
+/***************************************************/
+
+typedef struct osm_qos_level {
+ char *use;
+ char *name;
+ uint8_t sl;
+ boolean_t sl_set;
+ uint8_t mtu_limit;
+ boolean_t mtu_limit_set;
+ uint8_t rate_limit;
+ boolean_t rate_limit_set;
+ uint8_t pkt_life;
+ boolean_t pkt_life_set;
+ uint64_t **path_bits_range_arr; /* array of bit ranges (real values are 32bits) */
+ unsigned path_bits_range_len; /* num of bit ranges in the array */
+ uint64_t **pkey_range_arr; /* array of PKey ranges (real values are 16bits) */
+ unsigned pkey_range_len;
+} osm_qos_level_t;
+
+
+/***************************************************/
+
+typedef struct osm_qos_match_rule {
+ char *use;
+ cl_list_t source_list; /* list of strings */
+ cl_list_t source_group_list; /* list of pointers to relevant port-group */
+ cl_list_t destination_list; /* list of strings */
+ cl_list_t destination_group_list; /* list of pointers to relevant port-group */
+ char *qos_level_name;
+ osm_qos_level_t *p_qos_level;
+ uint64_t **service_id_range_arr; /* array of SID ranges (64-bit values) */
+ unsigned service_id_range_len;
+ uint64_t **qos_class_range_arr; /* array of QoS Class ranges (real values are 16bits) */
+ unsigned qos_class_range_len;
+ uint64_t **pkey_range_arr; /* array of PKey ranges (real values are 16bits) */
+ unsigned pkey_range_len;
+} osm_qos_match_rule_t;
+
+/***************************************************/
+
+typedef struct osm_qos_policy {
+ cl_list_t port_groups; /* list of osm_qos_port_group_t */
+ cl_list_t sl2vl_tables; /* list of osm_qos_sl2vl_scope_t */
+ cl_list_t vlarb_tables; /* list of osm_qos_vlarb_scope_t */
+ cl_list_t qos_levels; /* list of osm_qos_level_t */
+ cl_list_t qos_match_rules; /* list of osm_qos_match_rule_t */
+ osm_qos_level_t *p_default_qos_level; /* default QoS level */
+ osm_subn_t *p_subn; /* osm subnet object */
+ st_table * p_node_hash; /* node by name hash */
+} osm_qos_policy_t;
+
+/***************************************************/
+
+osm_qos_port_t *osm_qos_policy_port_create(osm_physp_t * p_physp);
+osm_qos_port_group_t * osm_qos_policy_port_group_create();
+void osm_qos_policy_port_group_destroy(osm_qos_port_group_t * p_port_group);
+
+osm_qos_vlarb_scope_t * osm_qos_policy_vlarb_scope_create();
+void osm_qos_policy_vlarb_scope_destroy(osm_qos_vlarb_scope_t * p_vlarb_scope);
+
+osm_qos_sl2vl_scope_t * osm_qos_policy_sl2vl_scope_create();
+void osm_qos_policy_sl2vl_scope_destroy(osm_qos_sl2vl_scope_t * p_sl2vl_scope);
+
+osm_qos_level_t * osm_qos_policy_qos_level_create();
+void osm_qos_policy_qos_level_destroy(osm_qos_level_t * p_qos_level);
+
+boolean_t osm_qos_level_has_pkey(IN const osm_qos_level_t * p_qos_level,
+ IN ib_net16_t 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);
+
+osm_qos_match_rule_t * osm_qos_policy_match_rule_create();
+void osm_qos_policy_match_rule_destroy(osm_qos_match_rule_t * p_match_rule);
+
+osm_qos_policy_t * osm_qos_policy_create(osm_subn_t * p_subn);
+void osm_qos_policy_destroy(osm_qos_policy_t * p_qos_policy);
+int osm_qos_policy_validate(osm_qos_policy_t * p_qos_policy, osm_log_t * p_log);
+
+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);
+
+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);
+
+/***************************************************/
+
+int osm_qos_parse_policy_file(IN osm_subn_t * const p_subn);
+
+/***************************************************/
+
+#endif /* ifndef OSM_QOS_POLICY_H */
diff --git a/contrib/ofed/management/opensm/include/opensm/osm_remote_sm.h b/contrib/ofed/management/opensm/include/opensm/osm_remote_sm.h
new file mode 100644
index 0000000..4cc980b
--- /dev/null
+++ b/contrib/ofed/management/opensm/include/opensm/osm_remote_sm.h
@@ -0,0 +1,198 @@
+/*
+ * 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_sm_t, osm_remote_sm_t.
+ * This object represents an IBA subnet.
+ * This object is part of the OpenSM family of objects.
+ */
+
+#ifndef _OSM_REMOTE_SM_H_
+#define _OSM_REMOTE_SM_H_
+
+#include <iba/ib_types.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_port.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/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 0000000..4901aca
--- /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 <iba/ib_types.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_mcast_tbl.h>
+#include <opensm/osm_port_profile.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/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 0000000..5a0ae9f
--- /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 <iba/ib_types.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_event.h>
+#include <complib/cl_thread.h>
+#include <complib/cl_timer.h>
+#include <complib/cl_dispatcher.h>
+#include <opensm/osm_stats.h>
+#include <opensm/osm_subnet.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_sa_mad_ctrl.h>
+#include <opensm/osm_sm.h>
+#include <opensm/osm_multicast.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/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 0000000..cc2ac53
--- /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 <complib/cl_dispatcher.h>
+#include <opensm/osm_stats.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_log.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/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 0000000..1d97a68
--- /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 <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_spinlock.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_log.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/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 0000000..ebe3dc3
--- /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 <iba/ib_types.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_event.h>
+#include <complib/cl_thread.h>
+#include <complib/cl_dispatcher.h>
+#include <complib/cl_event_wheel.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_stats.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_vl15intf.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_sm_mad_ctrl.h>
+#include <opensm/osm_lid_mgr.h>
+#include <opensm/osm_ucast_mgr.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_db.h>
+#include <opensm/osm_remote_sm.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/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 0000000..1c41168
--- /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 <complib/cl_passivelock.h>
+#include <complib/cl_dispatcher.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_stats.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_vl15intf.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/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 0000000..4331cfa
--- /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 <pthread.h>
+#else
+#include <complib/cl_event.h>
+#endif
+#include <complib/cl_atomic.h>
+#include <opensm/osm_base.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/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 0000000..d97d5f4
--- /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 <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_map.h>
+#include <complib/cl_ptr_vector.h>
+#include <complib/cl_list.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_prefix_route.h>
+#include <stdio.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 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 0000000..dbc22e5
--- /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 <iba/ib_types.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_mcast_tbl.h>
+#include <opensm/osm_port_profile.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/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 0000000..11335c7
--- /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 <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <opensm/osm_switch.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
+
+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 0000000..a040476
--- /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 <complib/cl_passivelock.h>
+#include <complib/cl_qlist.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_ucast_cache.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/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 0000000..697e2fd
--- /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 0000000..d783245
--- /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 0000000..028eec0
--- /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 <iba/ib_types.h>
+#include <complib/cl_spinlock.h>
+#include <complib/cl_event.h>
+#include <complib/cl_thread.h>
+#include <complib/cl_qlist.h>
+#include <opensm/osm_stats.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_mad_pool.h>
+#include <vendor/osm_vendor_api.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/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 0000000..30cc308
--- /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 <stdlib.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 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 0000000..3994d59
--- /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 <opensm/osm_helper.h>
+#include <vendor/osm_vendor_mtl.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_opensm.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/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 0000000..5a8ef5f
--- /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 <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_map.h>
+#include <complib/cl_ptr_vector.h>
+#include <complib/cl_list.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_path.h>
+#include <opensm/osm_madw.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/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 0000000..d68c924
--- /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 0000000..129627d
--- /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 <vendor/osm_vendor_api.h>
+#include <opensm/osm_log.h>
+#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 0000000..4d0ae4c
--- /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 <opensm/osm_config.h>
+
+#if defined( OSM_VENDOR_INTF_TEST )
+#include <vendor/osm_vendor_test.h>
+#elif defined( OSM_VENDOR_INTF_UMADT )
+#include <vendor/osm_vendor_umadt.h>
+#elif defined( OSM_VENDOR_INTF_MTL )
+/* HACK - I do not know how to prevent complib from loading kernel H files */
+#undef __init
+#include <vendor/osm_vendor_mlx.h>
+#elif defined( OSM_VENDOR_INTF_TS )
+#undef __init
+#include <vendor/osm_vendor_mlx.h>
+#elif defined( OSM_VENDOR_INTF_ANAFA )
+#undef __init
+#include <vendor/osm_vendor_mlx.h>
+#elif defined( OSM_VENDOR_INTF_SIM )
+#undef __init
+#include <vendor/osm_vendor_mlx.h>
+#elif defined( OSM_VENDOR_INTF_OPENIB )
+#include <vendor/osm_vendor_ibumad.h>
+#elif defined( OSM_VENDOR_INTF_AL )
+#include <vendor/osm_vendor_al.h>
+#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 0000000..e7371c9
--- /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 <iba/ib_types.h>
+#include <iba/ib_al.h>
+#include <complib/cl_qlist.h>
+#include <complib/cl_thread.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_log.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/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 0000000..70eb6cc
--- /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 <opensm/osm_madw.h>
+#include <opensm/osm_mad_pool.h>
+#include <vendor/osm_vendor.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 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 0000000..3a3f070
--- /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 <iba/ib_types.h>
+#include <complib/cl_qlist.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_log.h>
+
+#include <infiniband/common.h>
+#include <infiniband/umad.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/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 0000000..106e0b4
--- /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 <sys/types.h>
+#include <opensm/osm_log.h>
+#include <complib/cl_qlist.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
+/*
+ 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 0000000..d4c2c30
--- /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 <vendor/osm_vendor_mlx_inout.h>
+#include <opensm/osm_log.h>
+#include <vendor/osm_vendor_api.h>
+#include <vendor/osm_vendor_mlx_txn.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
+/* 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 0000000..ba83f30
--- /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 0000000..9b56943
--- /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 <vendor/osm_vendor.h>
+#include <vendor/osm_vendor_mlx_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
+#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 0000000..868639b
--- /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 <mtl_common.h>
+#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 <vapi_types.h>
+#include <evapi.h>
+#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 0000000..dac1f13
--- /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 <complib/cl_event.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_madw.h>
+#include <vendor/osm_vendor_mlx_sar.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 _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 0000000..a65b4f2
--- /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 <iba/ib_types.h>
+#include <complib/cl_qlist.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 _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 0000000..e849744
--- /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 <vendor/osm_vendor_mlx.h>
+#include <vendor/osm_vendor_mlx_txn.h>
+#include <opensm/osm_madw.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
+/****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 0000000..f23a77d
--- /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 <stdlib.h>
+#include <string.h>
+#include <iba/ib_types.h>
+#include <vendor/osm_vendor_mlx_defs.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
+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 0000000..2840e49
--- /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 <vendor/osm_vendor_mlx.h>
+#include <vendor/osm_vendor_mlx_defs.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_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 0000000..dac26ed
--- /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 0000000..ce59191
--- /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 <sys/types.h>
+#include <unistd.h>
+
+#include <complib/cl_qmap.h>
+#include <opensm/osm_madw.h>
+#include <complib/cl_event_wheel.h>
+
+#include <vendor/osm_vendor_mlx_rmpp_ctx.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 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 0000000..df48260
--- /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 <vapi_types.h>
+#include <evapi.h>
+#include <ib_mgt.h>
+#define IN
+#define OUT
+#include "iba/ib_types.h"
+#include "iba/ib_al.h"
+#include <complib/cl_thread.h>
+#include <complib/cl_types_osd.h>
+#include <opensm/osm_base.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/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 0000000..1b3da88
--- /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 0000000..6ec5b86
--- /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 <vapi_types.h>
+ #include <evapi.h>
+ */
+
+#include <iba/ib_types.h>
+#include <iba/ib_al.h>
+#include <complib/cl_qlist.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_timer.h>
+#include <complib/cl_thread.h>
+#include <complib/cl_types_osd.h>
+#include <complib/cl_spinlock.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_madw.h>
+#ifdef OSM_VENDOR_INTF_MTL
+#include <ib_mgt.h>
+#include <opensm/osm_mtl_bind.h>
+#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 0000000..4a4eeaf
--- /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 <iba/ib_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
+/****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 0000000..a1ae1eb
--- /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 <iba/ib_types.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_log.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
+/* 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 0000000..a43f4e4
--- /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 <vapi_types.h>
+#include <evapi.h>
+#include <ib/ts_api_ng/useraccess/include/ts_ib_useraccess.h>
+#define IN
+#define OUT
+#include "iba/ib_types.h"
+#include "iba/ib_al.h"
+#include <complib/cl_thread.h>
+#include <complib/cl_types_osd.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_log.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 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 0000000..8cdb631
--- /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 <opensm/osm_base.h>
+#include <vendor/umadt.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/ 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 0000000..c9648ec
--- /dev/null
+++ b/contrib/ofed/management/opensm/libvendor/ChangeLog
@@ -0,0 +1,64 @@
+2007-07-11 Hal Rosenstock <halr@voltaire.com>
+
+ * configure.in: Bump version to 2.2.1
+
+2007-07-10 Sean Hefty <sean.hefty@intel.com>
+
+ * 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 <halr@voltaire.com>
+
+ * osm_vendor_ibumad.(h c): Remove support for issmdisabled
+
+2007-03-29 Hal Rosenstock <halr@voltaire.com>
+
+ * configure.in: Bump version to 2.2.0
+
+2007-03-27 Hal Rosenstock <halr@voltaire.com>
+
+ * osm_vendor_ibumad.(h c): Add support for issmdisabled
+
+2007-03-13 Hal Rosenstock <halr@voltaire.com>
+
+ * osm_vendor_ibumad.c: In osm_vendor_set_sm, set issmfd to
+ -1 on open error
+
+2007-03-12 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * configure.in: Bump version to 2.1.1
+
+2007-02-20 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * 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 <sashak@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * osm_vendor_ibumad.c (umad_receiver): Fix endian of LID
+ displayed in send timeout error message.
+
+2006-10-10 Hal Rosenstock <halr@voltaire.com>
+
+ * osm_vendor_ibumad.c: Print errors to stderr rather than
+ stdout.
+
+2006-09-28 Eitan Zahavi <eitan@mellanox.co.il>
+
+ * 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 0000000..22f7a08
--- /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 0000000..17416b3
--- /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 0000000..0c3a85b
--- /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 0000000..3e77b56
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <vendor/osm_pkt_randomizer.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifndef WIN32
+#include <sys/time.h>
+#include <unistd.h>
+#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 0000000..d5d78c9
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#ifdef OSM_VENDOR_INTF_AL
+
+#include <stdlib.h>
+#include <string.h>
+#include <complib/cl_qlist.h>
+#include <complib/cl_thread.h>
+#include <complib/cl_math.h>
+#include <complib/cl_debug.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_mad_pool.h>
+#include <vendor/osm_vendor_api.h>
+
+/****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 0000000..734a860
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#ifdef OSM_VENDOR_INTF_OPENIB
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <iba/ib_types.h>
+#include <complib/cl_qlist.h>
+#include <complib/cl_math.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_helper.h>
+#include <vendor/osm_vendor_api.h>
+
+/****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 0000000..800b308
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <vendor/osm_vendor_api.h>
+#include <vendor/osm_vendor_sa_api.h>
+#include <complib/cl_event.h>
+
+/*****************************************************************************
+ *****************************************************************************/
+
+/* 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 0000000..683f56d
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <vendor/osm_vendor_mlx.h>
+#include <vendor/osm_vendor_mlx_transport.h>
+#include <vendor/osm_vendor_mlx_svc.h>
+#include <vendor/osm_vendor_mlx_sender.h>
+#include <vendor/osm_vendor_mlx_hca.h>
+#include <vendor/osm_pkt_randomizer.h>
+
+/**
+ * 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 0000000..bb04530
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/ioctl.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <vendor/osm_vendor_mlx.h>
+#include <vendor/osm_vendor_mlx_transport.h>
+#include <vendor/osm_vendor_mlx_transport_anafa.h>
+#include <vendor/osm_vendor_mlx_svc.h>
+#include <vendor/osm_vendor_mlx_sender.h>
+#include <vendor/osm_pkt_randomizer.h>
+#include <vendor/osm_ts_useraccess.h>
+
+/**
+ * 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 0000000..d476382
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <vendor/osm_vendor_mlx.h>
+#include <vendor/osm_vendor_mlx_defs.h>
+#include <vendor/osm_vendor_mlx_svc.h>
+#include <vendor/osm_vendor_mlx_transport.h>
+#include <vendor/osm_vendor_mlx_sender.h>
+#include <vendor/osm_pkt_randomizer.h>
+
+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 0000000..e98e272
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#if defined(OSM_VENDOR_INTF_MTL) | defined(OSM_VENDOR_INTF_TS)
+#undef IN
+#undef OUT
+#include <vapi_types.h>
+#include <evapi.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_log.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/********************************************************************************
+ *
+ * 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 0000000..81506e4
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#if defined(OSM_VENDOR_INTF_ANAFA)
+#undef IN
+#undef OUT
+
+#include <stdlib.h>
+#include <stddef.h>
+#include <string.h>
+
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_log.h>
+#include <sys/ioctl.h>
+
+#include <vendor/osm_vendor_mlx_transport_anafa.h>
+#include <vendor/osm_ts_useraccess.h>
+
+/********************************************************************************
+ *
+ * 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 0000000..512b7bf
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#if defined(OSM_VENDOR_INTF_MTL) | defined(OSM_VENDOR_INTF_TS)
+#undef IN
+#undef OUT
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_log.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <fcntl.h>
+
+/********************************************************************************
+ *
+ * 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 0000000..b6c0193
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#if defined(OSM_VENDOR_INTF_SIM)
+#undef IN
+#undef OUT
+
+#include <unistd.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_log.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <stdint.h>
+#include <fcntl.h>
+
+/******************************************************************************
+*
+* 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 0000000..9df6624
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ib_mgt.h>
+#include <complib/cl_event.h>
+#include <vendor/osm_vendor_mlx_transport.h>
+#include <vendor/osm_vendor_mlx_dispatcher.h>
+#include <opensm/osm_log.h>
+
+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 0000000..bbd42c3
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qlist.h>
+
+#include <vendor/osm_vendor_mlx_rmpp_ctx.h>
+#include <vendor/osm_vendor_mlx_svc.h>
+
+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 0000000..0257f32
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_timer.h>
+#include <complib/cl_event.h>
+#include <vendor/osm_vendor_api.h>
+#include <vendor/osm_vendor_sa_api.h>
+
+/*****************************************************************************
+ *****************************************************************************/
+
+/* 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 0000000..5523284
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <vendor/osm_vendor_mlx_sar.h>
+
+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 0000000..a0bdef8
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <vendor/osm_vendor_mlx_sender.h>
+#include <vendor/osm_vendor_mlx_transport.h>
+#include <vendor/osm_vendor_mlx_svc.h>
+#include <vendor/osm_pkt_randomizer.h>
+
+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 0000000..c02c4de
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <vendor/osm_vendor_api.h>
+#include <vendor/osm_vendor_mlx_transport.h>
+#include <vendor/osm_vendor_mlx_dispatcher.h>
+#include <vendor/osm_vendor_mlx_svc.h>
+#include <complib/cl_thread.h>
+
+/* the simulator messages definition */
+#include <ibmgtsim/ibms_client_api.h>
+
+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 0000000..d7ab3b3
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <vendor/osm_vendor_api.h>
+#include <vendor/osm_vendor_mlx_transport.h>
+#include <vendor/osm_vendor_mlx_dispatcher.h>
+#include <vendor/osm_vendor_mlx_svc.h>
+#include <vendor/osm_ts_useraccess.h>
+
+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 0000000..b88ac64
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <vendor/osm_vendor_api.h>
+#include <vendor/osm_vendor_mlx_transport.h>
+#include <vendor/osm_vendor_mlx_transport_anafa.h>
+#include <vendor/osm_vendor_mlx_dispatcher.h>
+#include <vendor/osm_vendor_mlx_svc.h>
+#include <vendor/osm_ts_useraccess.h>
+
+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 0000000..a2da75a
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+
+#include <vendor/osm_vendor_mlx.h>
+#include <vendor/osm_vendor_mlx_defs.h>
+#include <vendor/osm_vendor_mlx_txn.h>
+#include <vendor/osm_vendor_mlx_svc.h>
+#include <vendor/osm_vendor_mlx_sender.h>
+
+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 0000000..5fb05ef
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#ifdef OSM_VENDOR_INTF_MTL
+
+#include <stdlib.h>
+#include <string.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_log.h>
+/* HACK - I do not know how to prevent complib from loading kernel H files */
+#undef __init
+#include <vendor/osm_vendor_mtl.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_opensm.h>
+#include <vendor/osm_vendor_mtl_transaction_mgr.h>
+#include <vendor/osm_mtl_bind.h>
+
+/*
+ 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 0000000..d78af31
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#if defined(OSM_VENDOR_INTF_MTL) | defined(OSM_VENDOR_INTF_TS)
+#undef IN
+#undef OUT
+#include <stdlib.h>
+#include <vapi_types.h>
+#include <evapi.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_log.h>
+#include <stdio.h>
+
+/********************************************************************************
+ *
+ * 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 <stdio.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..6e8afb0
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <math.h>
+#include <stdlib.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_log.h>
+#include <vendor/osm_vendor.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_mad_pool.h>
+
+#if defined(OSM_VENDOR_INTF_MTL) | defined(OSM_VENDOR_INTF_TS)
+
+#include <vendor/osm_vendor_mtl_transaction_mgr.h>
+#ifdef OSM_VENDOR_INTF_MTL
+#include <vendor/osm_mtl_bind.h>
+#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 0000000..67fc0e2
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#ifdef OSM_VENDOR_INTF_TEST
+
+#include <stdlib.h>
+#include <string.h>
+#include <opensm/osm_log.h>
+#include <vendor/osm_vendor_test.h>
+#include <vendor/osm_vendor_api.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..710d06f
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <vendor/osm_vendor_ts.h>
+#include <vendor/osm_vendor_api.h>
+#include <vendor/osm_ts_useraccess.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_opensm.h>
+
+/*
+ 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 0000000..82932dd
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#ifdef OSM_VENDOR_INTF_UMADT
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <dlfcn.h>
+#include <string.h>
+
+#include <complib/cl_qlist.h>
+#include <complib/cl_thread.h>
+#include <complib/cl_timer.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_mad_pool.h>
+
+#include <vendor/osm_vendor_umadt.h>
+#include <vendor/osm_umadt.h>
+
+/* 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 0000000..3000eaf
--- /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 <file_name>]
+[\-c(reate-config) <file_name>]
+[\-g(uid) <GUID in hex>]
+[\-l(mc) <LMC>]
+[\-p(riority) <PRIORITY>]
+[\-smkey <SM_Key>]
+[\-r(eassign_lids)]
+[\-R <engine name(s)> | \-\-routing_engine <engine name(s)>]
+[\-A | \-\-ucast_cache]
+[\-z | \-\-connect_roots]
+[\-M <file name> | \-\-lid_matrix_file <file name>]
+[\-U <file name> | \-\-lfts_file <file name>]
+[\-S | \-\-sadb_file <file name>]
+[\-a | \-\-root_guid_file <path to file>]
+[\-u | \-\-cn_guid_file <path to file>]
+[\-X | \-\-guid_routing_order_file <path to file>]
+[\-m | \-\-ids_guid_file <path to file>]
+[\-o(nce)]
+[\-s(weep) <interval>]
+[\-t(imeout) <milliseconds>]
+[\-maxsmps <number>]
+[\-console [off | local | socket | loopback]]
+[\-console-port <port>]
+[\-i(gnore-guids) <equalize-ignore-guids-file>]
+[\-f <log file path> | \-\-log_file <log file path> ]
+[\-L | \-\-log_limit <size in MB>] [\-e(rase_log_file)]
+[\-P(config) <partition config file> ]
+[\-N | \-\-no_part_enforce]
+[\-Q | \-\-qos [\-Y | \-\-qos_policy_file <file name>]]
+[\-y | \-\-stay_on_fatal]
+[\-B | \-\-daemon]
+[\-I | \-\-inactive]
+[\-\-perfmgr]
+[\-\-perfmgr_sweep_time_s <seconds>]
+[\-\-prefix_routes_file <path>]
+[\-\-consolidate_ipv6_snm_req]
+[\-v(erbose)] [\-V] [\-D <flags>] [\-d(ebug) <number>]
+[\-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 <config file>
+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 <file name>
+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 <GUID in hex>
+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 <LMC value>
+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 <Priority value>
+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 <SM_Key value>
+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 <Routing engine names>
+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 <file name>
+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 <file name>
+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 <file name>
+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 <file name>
+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 <file name>
+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 <file name>
+Name of the map file with set of the IDs which will be used
+by Up/Down routing algorithm instead of node GUIDs
+(format: <guid> <id> per line).
+.TP
+\fB\-X\fR, \fB\-\-guid_routing_order_file\fR <file name>
+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 <interval value>
+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 <value>
+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 <number>
+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 <port>
+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 <equalize-ignore-guids-file>
+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 <file name>
+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 <size in MB>
+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 <partition config file>
+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 <file name>
+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 <file name>
+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 <seconds>
+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 <value>
+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 <value>
+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>:<PortGUIDs list> ;
+
+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=<val> - specifies rate for this IPoIB MC group
+ (default is 3 (10GBps))
+ mtu=<val> - specifies MTU for this IPoIB MC group
+ (default is 4 (2048))
+ sl=<val> - specifies SL for this IPoIB MC group
+ (default is 0)
+ scope=<val> - 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_<type>_"
+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 <equalize-ignore-guids-file>
+.br
+-ignore-guids <equalize-ignore-guids-file>
+ 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 <root_guid_file>' 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 <root_guid_file>' to provide root nodes for ranking. If the `-a' option
+is not used, routing algorithm will detect roots automatically.
+Use '-u <root_cn_file>' 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 0000000..3000eaf
--- /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 <file_name>]
+[\-c(reate-config) <file_name>]
+[\-g(uid) <GUID in hex>]
+[\-l(mc) <LMC>]
+[\-p(riority) <PRIORITY>]
+[\-smkey <SM_Key>]
+[\-r(eassign_lids)]
+[\-R <engine name(s)> | \-\-routing_engine <engine name(s)>]
+[\-A | \-\-ucast_cache]
+[\-z | \-\-connect_roots]
+[\-M <file name> | \-\-lid_matrix_file <file name>]
+[\-U <file name> | \-\-lfts_file <file name>]
+[\-S | \-\-sadb_file <file name>]
+[\-a | \-\-root_guid_file <path to file>]
+[\-u | \-\-cn_guid_file <path to file>]
+[\-X | \-\-guid_routing_order_file <path to file>]
+[\-m | \-\-ids_guid_file <path to file>]
+[\-o(nce)]
+[\-s(weep) <interval>]
+[\-t(imeout) <milliseconds>]
+[\-maxsmps <number>]
+[\-console [off | local | socket | loopback]]
+[\-console-port <port>]
+[\-i(gnore-guids) <equalize-ignore-guids-file>]
+[\-f <log file path> | \-\-log_file <log file path> ]
+[\-L | \-\-log_limit <size in MB>] [\-e(rase_log_file)]
+[\-P(config) <partition config file> ]
+[\-N | \-\-no_part_enforce]
+[\-Q | \-\-qos [\-Y | \-\-qos_policy_file <file name>]]
+[\-y | \-\-stay_on_fatal]
+[\-B | \-\-daemon]
+[\-I | \-\-inactive]
+[\-\-perfmgr]
+[\-\-perfmgr_sweep_time_s <seconds>]
+[\-\-prefix_routes_file <path>]
+[\-\-consolidate_ipv6_snm_req]
+[\-v(erbose)] [\-V] [\-D <flags>] [\-d(ebug) <number>]
+[\-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 <config file>
+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 <file name>
+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 <GUID in hex>
+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 <LMC value>
+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 <Priority value>
+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 <SM_Key value>
+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 <Routing engine names>
+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 <file name>
+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 <file name>
+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 <file name>
+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 <file name>
+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 <file name>
+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 <file name>
+Name of the map file with set of the IDs which will be used
+by Up/Down routing algorithm instead of node GUIDs
+(format: <guid> <id> per line).
+.TP
+\fB\-X\fR, \fB\-\-guid_routing_order_file\fR <file name>
+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 <interval value>
+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 <value>
+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 <number>
+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 <port>
+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 <equalize-ignore-guids-file>
+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 <file name>
+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 <size in MB>
+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 <partition config file>
+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 <file name>
+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 <file name>
+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 <seconds>
+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 <value>
+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 <value>
+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>:<PortGUIDs list> ;
+
+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=<val> - specifies rate for this IPoIB MC group
+ (default is 3 (10GBps))
+ mtu=<val> - specifies MTU for this IPoIB MC group
+ (default is 4 (2048))
+ sl=<val> - specifies SL for this IPoIB MC group
+ (default is 0)
+ scope=<val> - 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_<type>_"
+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 <equalize-ignore-guids-file>
+.br
+-ignore-guids <equalize-ignore-guids-file>
+ 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 <root_guid_file>' 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 <root_guid_file>' to provide root nodes for ranking. If the `-a' option
+is not used, routing algorithm will detect roots automatically.
+Use '-u <root_cn_file>' 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 0000000..c814b49
--- /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) <c|a|v|s|e|f|m|q|t>] [\-w(ait) <trap_wait_time>] [\-d(ebug) <number>]
+[\-m(ax_lid) <LID in hex>] [\-g(uid)[=]<GUID in hex>] [-p(ort)]
+[\-i(nventory) <filename>] [\-s(tress)] [\-M(ulticast_Mode)]
+[\-t(imeout) <milliseconds>] [\-l | \-\-log_file] [\-v] [\-vf <flags>]
+[\-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 0000000..9c23f47
--- /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 0000000..97eb67a
--- /dev/null
+++ b/contrib/ofed/management/opensm/opensm/ChangeLog
@@ -0,0 +1,115 @@
+2007-07-11 Hal Rosenstock <halr@voltaire.com>
+
+ * configure.in: Bump to version 2.2.1
+
+2007-06-20 Hal Rosenstock <halr@voltaire.com>
+
+ * osm_helper.c: Add 3LeafNetworks and Xsigo to osm_get_manufacturer_str
+
+2007-06-15 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * osm_helper.c: Fix PortInfo:CapMask printing when CapMask is 0
+
+2007-06-11 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * osm_helper.c: Remove OSM_SM_SIGNAL_MASTER_OR_HIGHER_SM_DETECTED
+ from __osm_sm_mgr_signal_str
+
+2007-06-06 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * osm_helper.c: More optimally deal with manufacturer strings
+
+2007-06-06 Hal Rosenstock <halr@voltaire.com>
+
+ * osm_helper.c: Add Sun to osm_get_manufacturer_str
+
+2007-06-04 Hal Rosenstock <halr@voltaire.com>
+
+ * osm_helper.c: Add 8x to __osm_lwa_str_fixed_width
+
+2007-05-07 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * osm_helper.c: Remove repeated strlen() calls
+
+2007-04-27 Ira K. Weiny <weiny2@llnl.gov>
+
+ * osm_helper.c: In osm_dump_notice, use ib_get_producer_type_str
+ for printing producer type
+
+2007-04-26 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <kliteyn@dev.mellanox.co.il>
+
+ * osm_helper.c: Fix problematic usage of sprintf() when
+ source and destination strings overlap.
+
+2007-04-24 Albert L. Chu <chu11@llnl.gov>
+
+ * 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 <halr@voltaire.com>
+
+ * configure.in: Bump version to 2.2.0
+
+2007-03-21 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * osm_log.c: Changed to support daemon mode
+
+2007-03-01 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <sashak@voltaire.com>
+
+ * osm_log.c: Minor optimization to previous change to osm_log
+ for also flushing on OSM_LOG_SYS
+
+2007-02-26 Yevgeny Kliteynik <kliteyn@dev.mellanox.co.il>
+
+ * osm_log.c: In osm_log, flush log on OSM_LOG_SYS (as well
+ as OSM_LOG_ERROR)
+
+2007-02-20 Hal Rosenstock <halr@voltaire.com>
+
+ * 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 <halr@voltaire.com>
+
+ * osm_helper.c: Change DR path format from [%X] to %d,
+
+2007-01-08 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * osm_log.c: Add osm_log_reopen_file API
+
+2006-12-22 Hal Rosenstock <halr@voltaire.com>
+
+ * osm_helper.c: Add osm_dump_switch_info_record API
+
+2006-11-03 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * osm_log.c: Add osm_log_printf API
+
+2006-10-30 Sasha Khapyorsky <sashak@voltaire.com>
+
+ * osm_helper.c: Fix seg fault with strings which
+ might not be null terminated
+
+2006-10-18 Yevgeny Kliteynik <kliteyn@dev.mellanox.co.il>
+
+ * osm_log.c: Windows porting changes
+
+2006-09-19 Yevgeny Kliteynik <kliteyn@dev.mellanox.co.il>
+
+ * 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 0000000..66fbccc
--- /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 0000000..7cd2aba
--- /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 0000000..f552dd0
--- /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 0000000..999e92f
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <complib/cl_types.h>
+#include <complib/cl_debug.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_version.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_console.h>
+#include <opensm/osm_console_io.h>
+#include <opensm/osm_perfmgr.h>
+
+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 <file-name>\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 <file-name>\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 <GUID in hex>\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 <LMC>\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 <PRIORITY>\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 <SM_Key>\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 <engine name>\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 <file name>\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 <file name>\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 <file name>\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 <path to file>\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 <path to file>\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 <path to file>\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: <guid> <id> per line)\n\n");
+ printf("--guid_routing_order_file, -X <path to file>\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 <interval>\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 <milliseconds>\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 <number>\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 <port>\n"
+ " Specify an alternate telnet port for the console (default %d).\n\n",
+ OSM_DEFAULT_CONSOLE_PORT);
+#endif
+ printf("--ignore-guids, -i <equalize-ignore-guids-file>\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 <log-file-name>\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 <size in MB>\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 <partition-config-file>\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 <QoS-policy-file>\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 <sec.>\n"
+ " PerfMgr sweep interval in seconds.\n\n");
+#endif
+ printf("--prefix_routes_file <path to 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 <flags>\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 <number>\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 0000000..3f30c3c
--- /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] <file list>\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 0000000..3a87cfd
--- /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, "<osm_error_codes")) {
+ @ERR_DEFS = <ERRS>;
+ close(ERRS);
+ foreach $errDef (@ERR_DEFS) {
+ # the format should be <file name> <err prefix> <last err>
+ 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 = <INFILE>;
+ close(INFILE);
+ $any_fix = 0;
+ $needed_fixing = 0;
+ $need_indentation = 0;
+
+ LINE: for ($line_num = 0; $line_num <scalar(@LINES); $line_num++) {
+ $line = $LINES[$line_num];
+ $_ = $line;
+
+ # 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;
+ }
+
+
+ # Error on C++ style comment lines
+ if( /\/\// )
+ {
+ print "C++ style comment on $file_name $line_num\n";
+ $needed_fixing++;
+ if ($fix_mode) {
+ $line =~ s=\/\/(.*)$=/* \1 */=;
+ if (confirm_change($line, $LINES[$line_num])) {
+ $LINES[$line_num] = $line;
+ $any_fix++;
+ }
+ $any_fix++;
+ }
+ }
+
+ # check for lines with trailing spaces:
+ if (/[ \t]+$/) {
+ $needed_fixing++;
+ if ($fix_mode) {
+ $line =~ s/\s+$/\n/;
+ if (confirm_change($line, $LINES[$line_num])) {
+ $LINES[$line_num] = $line;
+ $any_fix++;
+ }
+ $any_fix++;
+ }
+ }
+
+ # check for bad PRIx64 usage
+ # It's a common mistake to forget the % before the PRIx64
+ if (/[^%0-9][0-9]*\"\s*PRIx64/ ) {
+ $needed_fixing++;
+ print "No % sign before PRx64!!: $file_name $line_num\n";
+ if ($fix_mode) {
+ $line =~ s/([0-9]*)\"\s*PRIx64/%$1\" PRIx64/;
+ if (confirm_change($line, $LINES[$line_num])) {
+ $LINES[$line_num] = $line;
+ $any_fix++;
+ }
+ }
+ }
+
+ # This simple script doesn't handle checking PRIx64 usage
+ # when PRIx64 starts the line. Just give a warning.
+ if( /^\s*PRIx64/ )
+ {
+ $needed_fixing++;
+ print "Warning: PRIx64 at start of line. $file_name $line_num\n";
+# if ($fix_mode) {
+# print "Fatal: can not auto fix\n";
+# exit 1;
+# }
+ }
+
+ # 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 $file_name: $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!! $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] <file list>\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 = <STDIN>;
+ 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 0000000..c6e8e59
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#define _GNU_SOURCE /* for getline */
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+#include <arpa/inet.h>
+#endif
+#include <unistd.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/time.h>
+#include <opensm/osm_console.h>
+#include <complib/cl_passivelock.h>
+#include <opensm/osm_perfmgr.h>
+#include <opensm/osm_subnet.h>
+
+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 [<command>]\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 [<log-level>]\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 [<sm-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<ret>\" 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 <nodename|nodeguid>] -- 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, " <none>");
+ }
+ 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<ret>\" 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 0000000..3d3ece4
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#define _GNU_SOURCE /* for getline */
+#ifdef ENABLE_OSM_CONSOLE_SOCKET
+#include <tcpd.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#endif
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <opensm/osm_console_io.h>
+
+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 0000000..907b7c7
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <opensm/st.h>
+#include <opensm/osm_db.h>
+
+/****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 <stdlib.h>
+#include <math.h>
+
+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 0000000..bf56169
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_db_pack.h>
+
+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 0000000..215a155
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_ptr_vector.h>
+#include <opensm/osm_sm.h>
+#include <opensm/osm_router.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_mcm_info.h>
+#include <opensm/osm_multicast.h>
+#include <opensm/osm_remote_sm.h>
+#include <opensm/osm_inform.h>
+#include <opensm/osm_ucast_mgr.h>
+
+/**********************************************************************
+ **********************************************************************/
+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(&notice, 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, &notice);
+ 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 0000000..7e0ba47
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_opensm.h>
+
+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 0000000..b0dc549
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <opensm/osm_event_plugin.h>
+#include <opensm/osm_opensm.h>
+
+#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 0000000..51fb894
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <complib/cl_debug.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_log.h>
+
+#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 0000000..4da000f
--- /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 0000000..1331d75
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_inform.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_sa.h>
+#include <sys/socket.h>
+
+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 0000000..b74aba5
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_lid_mgr.h>
+#include <opensm/osm_sm.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_msgdef.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_db_pack.h>
+
+/**********************************************************************
+ 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 0000000..c3d8633
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_sm.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..37e3e1b
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_sm.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_msgdef.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..88633ab
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <opensm/osm_log.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <errno.h>
+
+static int log_exit_count = 0;
+
+#ifndef WIN32
+#include <sys/time.h>
+#include <unistd.h>
+#include <complib/cl_timer.h>
+
+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 0000000..56a2a6d
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_madw.h>
+#include <vendor/osm_vendor_api.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..635c7da
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_sm.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..2f9cb5e
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_sm.h>
+#include <opensm/osm_multicast.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_msgdef.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..17fb69c
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <complib/cl_math.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_mcast_tbl.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..0325a34
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <opensm/osm_mcm_info.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..b6b6149
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <opensm/osm_mcm_port.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..3832e7d
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_mtree.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..350fd22
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <opensm/osm_multicast.h>
+#include <opensm/osm_mcm_port.h>
+#include <opensm/osm_mtree.h>
+#include <opensm/osm_inform.h>
+
+/**********************************************************************
+ **********************************************************************/
+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(&notice, 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(&notice.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, &notice)))
+ 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 0000000..07371a2
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_madw.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..f6178b9
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_subnet.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..c52c0d5
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_router.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_ucast_mgr.h>
+
+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 0000000..7de2e5b
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <complib/cl_dispatcher.h>
+#include <complib/cl_passivelock.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_version.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_sm.h>
+#include <opensm/osm_vl15intf.h>
+#include <opensm/osm_event_plugin.h>
+
+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 0000000..f7da2dc
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#ifdef ENABLE_OSM_PERF_MGR
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <poll.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <float.h>
+#include <arpa/inet.h>
+#include <iba/ib_types.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_thread.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_perfmgr.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_opensm.h>
+
+#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 0000000..934be77
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#ifdef ENABLE_OSM_PERF_MGR
+
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <dlfcn.h>
+#include <sys/stat.h>
+
+#include <opensm/osm_perfmgr_db.h>
+#include <opensm/osm_perfmgr.h>
+#include <opensm/osm_opensm.h>
+
+/** =========================================================================
+ */
+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 0000000..4666186
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <complib/cl_debug.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_helper.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..ae16eb6
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_partition.h>
+#include <opensm/osm_opensm.h>
+
+/**********************************************************************
+ **********************************************************************/
+/*
+ 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 0000000..7061941
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_sm.h>
+
+/**********************************************************************
+ **********************************************************************/
+/*
+ * 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 0000000..4b4d4b8
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <complib/cl_debug.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_mcm_info.h>
+#include <opensm/osm_switch.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..8763b87
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_remote_sm.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_ucast_mgr.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..be51410
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <complib/cl_debug.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_partition.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_sa.h>
+#include <opensm/osm_multicast.h>
+
+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 0000000..d663fad
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+
+#include <iba/ib_types.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_partition.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_log.h>
+
+#include <complib/cl_byteswap.h>
+
+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) & conf->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<<scope);
+ } else if (!strncmp(flag, "sl", len)) {
+ unsigned sl;
+ char *end;
+
+ if (!val || !*val || (sl = strtoul(val, &end, 0)) > 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 = &part;
+
+ 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 0000000..b451c25
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_qos_policy.h>
+
+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 0000000..ecdee8a
--- /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 <opensm/osm_qos_policy.h>
+#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 0000000..6b5a9b1
--- /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 <stdio.h>
+#include <assert.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_qos_policy.h>
+
+#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 0000000..094fef2
--- /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 <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_partition.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_qos_policy.h>
+
+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)<<osm_node_get_type(p_node)) )
+ return TRUE;
+
+ /* check whether this port's guid is in group's port map */
+
+ if (cl_qmap_get(&p_port_group->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 0000000..96bfd78
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <opensm/osm_remote_sm.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..0865ce5
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_attrib_req.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_vl15intf.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_opensm.h>
+
+/**********************************************************************
+ 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 0000000..9cd44f5
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_attrib_req.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_vl15intf.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_opensm.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..cb5a236
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_router.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..185557f
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_sa.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_multicast.h>
+#include <opensm/osm_inform.h>
+#include <opensm/osm_service.h>
+#include <opensm/osm_helper.h>
+#include <vendor/osm_vendor_api.h>
+
+#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 0000000..a3a2782
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_sa.h>
+
+#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 0000000..39dae72
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_sa.h>
+
+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 0000000..a48b546
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <arpa/inet.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_sa.h>
+#include <opensm/osm_inform.h>
+#include <opensm/osm_pkey.h>
+
+#include <sys/socket.h>
+
+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 0000000..d84a6a5
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_sa.h>
+
+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 0000000..b92845e
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_debug.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_sa.h>
+
+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 0000000..49309f9
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <complib/cl_debug.h>
+#include <iba/ib_types.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_sa_mad_ctrl.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_sa.h>
+
+/****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 0000000..37e78b5
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_inform.h>
+#include <opensm/osm_sa.h>
+
+#include <sys/socket.h>
+
+#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><Sc>,<Si>,<Si>,<P>,<P>,<P>,<P>,<P>,<P>,<P>,<P>,<Id>,<Id>,<Id>,<Id>
+ * 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|<IPoIB signature>|< P_Key >|00.......0|<all 1's>|
+ * +--------+----+----+-----------------+---------+----------+---------+
+ *
+ * For IPv6 over IB, the signature will be "0x601B".
+ *
+ * | 8 | 4 | 4 | 16 bits | 16 bits | 80 bits |
+ * +--------+----+----+-----------------+---------+--------------------+
+ * |11111111|0001|scop|<IPoIB signature>|< 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 0000000..bda9aee
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_sa.h>
+
+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 0000000..b9164be
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#if defined (VENDOR_RMPP_SUPPORT) && defined (DUAL_SIDED_RMPP)
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_partition.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_qos_policy.h>
+#include <opensm/osm_sa.h>
+
+#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 0000000..4df2c91
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_sa.h>
+
+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 0000000..6fdada7
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <arpa/inet.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_base.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_multicast.h>
+#include <opensm/osm_partition.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_qos_policy.h>
+#include <opensm/osm_sa.h>
+#include <opensm/osm_router.h>
+#include <opensm/osm_prefix_route.h>
+
+#include <sys/socket.h>
+
+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 0000000..70c6047
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_sa.h>
+
+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 0000000..753c3db
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_sa.h>
+
+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 0000000..66b4cb7
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_sa.h>
+#include <opensm/osm_service.h>
+#include <opensm/osm_pkey.h>
+
+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 0000000..0550fc1
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_sa.h>
+
+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 0000000..de99065
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_remote_sm.h>
+#include <opensm/osm_sa.h>
+#include <opensm/osm_opensm.h>
+
+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 0000000..649b0ac
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_sa.h>
+
+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 0000000..3bc9b8a
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_pkey.h>
+#include <opensm/osm_sa.h>
+
+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 0000000..b7c1270
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_timer.h>
+#include <opensm/osm_service.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..e177345
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_sm.h>
+
+/**********************************************************************
+ **********************************************************************/
+/*
+ * 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 0000000..649ff2a
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_thread.h>
+#include <opensm/osm_sm.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_mcm_info.h>
+#include <opensm/osm_perfmgr.h>
+#include <opensm/osm_opensm.h>
+
+#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 0000000..267ec85
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <complib/cl_debug.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_sm_mad_ctrl.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_opensm.h>
+
+/****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 0000000..343a9e3
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <time.h>
+#include <iba/ib_types.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_sm.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_port.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_opensm.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..98c1994
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_sm.h>
+#include <opensm/osm_opensm.h>
+
+/**********************************************************************
+ 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 0000000..625e026
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qmap.h>
+#include <opensm/osm_sm.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_port.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_inform.h>
+#include <opensm/osm_opensm.h>
+
+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(&notice, 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, &notice);
+ 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 0000000..c41962d
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <limits.h>
+#include <errno.h>
+#include <ctype.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_log.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_port.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_remote_sm.h>
+#include <opensm/osm_partition.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_multicast.h>
+#include <opensm/osm_inform.h>
+#include <opensm/osm_console.h>
+#include <opensm/osm_perfmgr.h>
+#include <opensm/osm_event_plugin.h>
+#include <opensm/osm_qos_policy.h>
+
+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^<packet_life_time>\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^<head_of_queue_lifetime>\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^<subnet_timeout>\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 0000000..ce86adb
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_opensm.h>
+
+/**********************************************************************
+ 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 0000000..9807791
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <complib/cl_math.h>
+#include <iba/ib_types.h>
+#include <opensm/osm_switch.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..46fbad7
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_inform.h>
+#include <opensm/osm_opensm.h>
+
+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 0000000..c89e24d
--- /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 <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_pool.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_ucast_mgr.h>
+#include <opensm/osm_ucast_cache.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_port.h>
+
+#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 0000000..2505c46
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_log.h>
+
+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 0000000..aa51d23
--- /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 <config.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_switch.h>
+
+/*
+ * 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 0000000..f6795f6
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qmap.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_log.h>
+
+/* //////////////////////////// */
+/* 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 0000000..d332b36
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qlist.h>
+#include <opensm/osm_ucast_mgr.h>
+#include <opensm/osm_sm.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_msgdef.h>
+#include <opensm/osm_opensm.h>
+
+/**********************************************************************
+ **********************************************************************/
+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 0000000..bb9ccda
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_qmap.h>
+#include <opensm/osm_switch.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_ucast_mgr.h>
+
+/* //////////////////////////// */
+/* 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 0000000..0703a4f
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_thread.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_vl15intf.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_helper.h>
+
+/**********************************************************************
+ **********************************************************************/
+
+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 0000000..ec04d67
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <string.h>
+#include <iba/ib_types.h>
+#include <complib/cl_passivelock.h>
+#include <complib/cl_debug.h>
+#include <opensm/osm_madw.h>
+#include <opensm/osm_log.h>
+#include <opensm/osm_node.h>
+#include <opensm/osm_subnet.h>
+#include <opensm/osm_helper.h>
+#include <opensm/osm_sm.h>
+
+/**********************************************************************
+ **********************************************************************/
+/*
+ * 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 0000000..c5a2f53
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <stdio.h>
+#include <string.h>
+#include <opensm/st.h>
+
+#ifdef _WIN32
+#include <malloc.h>
+#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 0000000..79e3d55
--- /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 0000000..346d1f3
--- /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 0000000..f755ff6
--- /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 0000000..f0781eb
--- /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 <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+#include <dlfcn.h>
+#include <stdint.h>
+#include <complib/cl_qmap.h>
+#include <complib/cl_passivelock.h>
+#include <opensm/osm_version.h>
+#include <opensm/osm_opensm.h>
+#include <opensm/osm_log.h>
+
+/** =========================================================================
+ * 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 0000000..4c68852
--- /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 0000000..bc796cc
--- /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 <vendor/osm_vendor_mlx_inout.h>
+#include <ib_mgt.h>
+#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 0000000..3fd6e9d
--- /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 <vapi.h>
+#include <evapi.h>
+#include <vapi_common.h>
+#include <ib_defs.h>
+
+#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 0000000..c3134ef
--- /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 <complib/cl_qmap.h>
+#include <opensm/osm_log.h>
+#include <vendor/osm_vendor_api.h>
+#include <vendor/osm_vendor_sa_api.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_helper.h>
+#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 0000000..7c33da3
--- /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 <limits.h>
+#else
+#include <vendor/winosm_common.h>
+#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 0000000..09063dd
--- /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 <stdlib.h>
+#include <complib/cl_qmap.h>
+#include <opensm/osm_log.h>
+#include <vendor/osm_vendor_api.h>
+#include <opensm/osm_mad_pool.h>
+#include <opensm/osm_helper.h>
+
+/****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 0000000..f87e33b
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <getopt.h>
+#include <complib/cl_debug.h>
+#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 <c|a|v|s|e|f|m|q|t>\n"
+ "--flow <c|a|v|s|e|f|m|q|t>\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 <trap_wait_time>\n"
+ "--wait <trap_wait_time>\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 <number>\n"
+ "--debug <number>\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 <LID in hex>\n"
+ "--max_lid <LID in hex>\n"
+ " This option specifies the maximal LID number to be searched\n"
+ " for during inventory file build (default to 100)\n\n");
+ printf("-g <GUID in hex>\n"
+ "--guid <GUID in hex>\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 <filename>\n"
+ "--inventory <filename>\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 <milliseconds>\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 <flags>\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 0000000..c252a4c
--- /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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <complib/cl_debug.h>
+#include <vendor/osm_vendor_mlx_hca.h>
+#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 0000000..6374dc2
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <mtl_common.h>
+#include <vapi.h>
+#include <evapi.h>
+#include <vapi_common.h>
+#include <ib_defs.h>
+#include <osmt_mtl_regular_qp.h>
+#include <complib/cl_types.h>
+/*
+ * 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 0000000..165457c
--- /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 <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <arpa/inet.h>
+#include <complib/cl_debug.h>
+#include <complib/cl_map.h>
+#include <complib/cl_list.h>
+#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 0000000..97f1492
--- /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 <unistd.h>
+#else
+#include <time.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <complib/cl_debug.h>
+#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 0000000..82a6f39
--- /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 <unistd.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <complib/cl_debug.h>
+#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 0000000..243d0b2
--- /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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef __WIN__
+#include <complib/cl_timer.h>
+#else
+#include <strings.h>
+#include <sys/time.h>
+#endif
+#include <complib/cl_debug.h>
+#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 <attr_id> 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 0000000..52293eb
--- /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 0000000..e16e227a
--- /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 0000000..2cc02e6
--- /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 0000000..9c22275
--- /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 0000000..f7635fe
--- /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
OpenPOWER on IntegriCloud